Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

theopavlakou

macrumors newbie
Original poster
Jul 20, 2011
7
0
Hey,
I have made a program that basically takes 2 parents blood groups (genotypes) and finds all the combinations that the baby's genotype could be, stores it in an NSArray and then selects a random one for the baby.

i.e. if the genotypes were OA for the father and BO for the mother, the baby's possible genotypes would be: OB, OO, AB, AO.

The problem however is that the array initially seems to store all the right values, but when it saves it returns the array later it seems to save an array of only AO (it saves this 4 times) and so the baby no matter what seems to have AO always.

Here is the code:

Human.h

Code:
#import <Cocoa/Cocoa.h>
#import "ArrayCategory.h"
#import "BloodType.h"

@class BloodType;


@interface Human : NSObject
{
	BloodType * blood;
	
}

-(Human *) makeBabyWith: (Human *) other;
-(id) init;
-(void) dealloc;


@property (nonatomic, retain) BloodType * blood;



@end


Human.m

Code:
#import "Human.h"

@implementation Human

-(Human *) makeBabyWith: (Human *) other
{
	Human * baby = [[Human alloc]init];
	
	NSArray * arr = [NSArray arrayWithArray:[self.blood getAllCombosWith: other.blood]];
	
	baby.blood = [arr tpRandomObject];
	[arr release];
	
	//baby.blood = [[self.blood getAllCombosWith: other.blood] tpRandomObject];
	
	return baby;
}

-(id) init
{
	if (self =[super init])
	{
	
		
		blood = [[BloodType alloc] init ];
	
		nos = 3;
		
	}
	return (self);

}

-(void) dealloc
{
	[blood release];
	[super dealloc];
}

-(NSString *) description
{
	return [self.blood description];
}


@synthesize blood, nos;

@end
BloodType.h
Code:
#import <Cocoa/Cocoa.h>
#import "ArrayCategory.h"


typedef enum {O = 1, A, B} bloodType;

@interface BloodType : NSObject 
{
	bloodType allele1;
	bloodType allele2;
	int number;

}


-(NSString *) alleleAsString;
-(NSMutableArray *) getAllCombosWith: (BloodType *) otherBlood;

@property bloodType allele1;
@property  bloodType allele2;
@property int number;
@end

BloodType.m

Code:
#import "BloodType.h"


@implementation BloodType

-(NSArray *) getAllCombosWith: (BloodType *) otherBlood
{
	NSMutableArray * array = [NSMutableArray arrayWithCapacity:4];
	BloodType * tempBlood = [[BloodType alloc]init];
	tempBlood.allele1 = self.allele1;
	tempBlood.allele2 = otherBlood.allele1; //OB
	[array addObject:tempBlood];
	
	tempBlood.allele1 = self.allele1;
	tempBlood.allele2 = otherBlood.allele2;
	[array addObject:tempBlood]; //OO

	tempBlood.allele1 = self.allele2;
	tempBlood.allele2 = otherBlood.allele1;
	[array addObject:tempBlood]; //AB

	tempBlood.allele1 = self.allele2;
	tempBlood.allele2 = otherBlood.allele2;
	[array addObject:tempBlood]; //AO
	
	[tempBlood release];
	
	return array;
}

-(NSString *) alleleAsString
{
	//NSDictionary * dict = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt: 0],@"O", [NSNumber numberWithInt: 1], @"A",[NSNumber numberWithInt: 2], @"B", nil];
	
	NSMutableString * a1 = [[NSMutableString alloc]init];
	NSMutableString * a2 = [[NSMutableString alloc]init];

	
	switch (self.allele1) {
		case O:
			[a1 appendString: @"O"];
			break;
		case A:
			[a1 appendString: @"A"];
			break;
		case B:
			[a1 appendString: @"B"];
			break;
		default:[a1 appendString: @"***There was an error!***"];
			break;
	}
	
	//NSLog(@"this is %@", a1);
	
	switch (self.allele2) {
		case O:
			[a2 appendString: @"O"];
			break;
		case A:
			[a2 appendString: @"A"];
			break;
		case B:
			[a2 appendString: @"B"];
			break;
		default:[a2 appendString: @"***There was an error!***"];
			break;
	}
	
	//NSLog(@"this is %@", a2);

	
	[a1 autorelease];
	[a2 autorelease];
	
	NSString * retString = [NSString stringWithFormat: @"blood genotype is %@ %@", a1  , a2];
	[retString autorelease];
	
	return (retString);
	

	
	
	//return (@"My blood genotype is %@ %@", [dict objectForKey: [NSNumber numberWithInt: self.allele1]], 
	//		[dict objectForKey: [NSNumber numberWithInt: self.allele2]]); //Check how to fix
	
	
}
ArrayCategory.h
Code:
#import <Cocoa/Cocoa.h>


@interface NSArray (ArrayCategory)

-(id) tpRandomObject;

@end
ArrayCategory.m
Code:
#import "ArrayCategory.h"


@implementation NSArray (ArrayCategory)

-(id) tpRandomObject
{
	
	long int x = arc4random();

	int y = x % 4;
	
	return [self objectAtIndex: y];
}

@end
main.m
Code:
#import <Foundation/Foundation.h>
#import "Human.h"
#import "BloodType.h"
#import "ArrayCategory.h"


int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
	Human * Joe = [[Human alloc]init];
    Human * Jenny = [[Human alloc]init];
	Human * baby = [[Human alloc]init];
	
	
	Joe.blood.allele1 = O;
	Joe.blood.allele2 = A;
	//NSLog(@"%@", Joe);
	NSLog(@"Joe's %@ ", [Joe.blood description]);


	Jenny.blood.allele1 = B;
	Jenny.blood.allele2 = O;
	NSLog(@"Jenny says \"My %@\"", Jenny);

	[Joe.blood setNumber: 5];
	[Joe setNos:6];
	
	baby = [Joe makeBabyWith: Jenny];
	NSLog(@"The baby's %@", baby);
	// The baby's blood genotype is A O
	
	
	NSLog(@"%i", [Joe retainCount] ); //1
	NSLog(@"%i", [Jenny retainCount] ); //1
	NSLog(@"%i", [baby retainCount] ); //1
	NSLog(@"%i", [Joe.blood retainCount] ); //1


	
	[Joe release];
	[Jenny release];
	[baby release];
    [pool drain];
    return 0;
}
And that's it, I'm not sure if I have outlined the problem enough, but please if you could help, please do.
 
Last edited by a moderator:
You're problem is in getAllCombosWith:

Adding an object to an array doesn't add a copy of the object, it just retains the object

So in getAllCombosWith: you only creating one BloodType object which you keep adding and changing. You need to create and add 4 BloodType objects.
 
You could eliminate the NSArray completely.

Randomly choose between the father's two alleles (50% probability).
Randomly choose between the mother's two alleles (50% probability).
Make a new BloodType from the two chosen alleles.

No NSArray is needed. No category on NSArray is needed. No temporary BloodType objects filling the array are needed.
 
Thank you

Hey man thanks a lot, I still haven't got it working but I am starting to understand what you are trying to explain to me. Please have a little more patience with me when I ask this :p Why doesn't this work then? I get an EXC_BAD_ACCESS error with it. Sorry, memory management is something I have to start understanding a little bit more:

New method:

-(NSMutableArray *) getAllCombosWith: (BloodType *) otherBlood
{
NSMutableArray * array = [NSMutableArray arrayWithCapacity:4];

BloodType * tempBlood = [[BloodType alloc]init];
tempBlood.allele1 = self.allele1;
tempBlood.allele2 = otherBlood.allele1;
NSLog(@"%@", tempBlood);
[array addObject:tempBlood];
[tempBlood release];

NSLog(@"Retain count of tempBlood is: %i", [tempBlood retainCount]);


BloodType * tempBlood2 = [[BloodType alloc]init];
//NSLog(@"Retain count is: %@", [tempBlood retainCount]);

tempBlood2.allele1 = self.allele2;
tempBlood2.allele2 = otherBlood.allele2;
NSLog(@"%@", tempBlood2);
[array addObject:tempBlood2];
[tempBlood2 release];


BloodType * tempBlood3 = [[BloodType alloc]init];
tempBlood3.allele1 = self.allele1;
tempBlood3.allele2 = otherBlood.allele2;
NSLog(@"%@", tempBlood3);
[array addObject:tempBlood3];
[tempBlood3 release];

BloodType * tempBlood4 = [[BloodType alloc]init];
tempBlood4.allele1 = self.allele2;
tempBlood4.allele2 = otherBlood.allele1;
NSLog(@"%@", tempBlood4);
[array addObject:tempBlood4];
[tempBlood4 release];

NSLog(@"Retain count of tempBlood is: %i", [tempBlood retainCount]);

//NSLog(@"Retain count is: %i", [array retainCount]);

for (BloodType * blood in array) //Fast enumeration
{
NSLog(@"%@", blood);
}


[tempBlood release];
[tempBlood2 release];
[tempBlood3 release];
[tempBlood4 release];


NSArray * arr2 = [NSArray arrayWithArray: array];
[arr2 writeToFile: @"/Users/theopavlakou/Desktop/blood.txt" atomically: YES];

return array;
}
 
You could eliminate the NSArray completely.

Randomly choose between the father's two alleles (50% probability).
Randomly choose between the mother's two alleles (50% probability).
Make a new BloodType from the two chosen alleles.

No NSArray is needed. No category on NSArray is needed. No temporary BloodType objects filling the array are needed.

Hey man, yeah I know I can do that too, but the reason I'm doing it like this is because I'm new to Obj C (and to object oriented programming in general) and I want to understand memory management basically. But thanks :)
 
Okay, i finally got it working, but I am worried about memory management, now, as I have gathered my retain count on all tempBloods is 2, and I haven't released them, this isn't healthy right?


-(NSMutableArray *) getAllCombosWith: (BloodType *) otherBlood
{
NSMutableArray * array = [NSMutableArray arrayWithCapacity:4];

BloodType * tempBlood = [[BloodType alloc]init];
tempBlood.allele1 = self.allele1;
tempBlood.allele2 = otherBlood.allele1;
NSLog(@"%@", tempBlood);
[array addObject: tempBlood];


NSLog(@"Retain count of tempBlood is: %i", [tempBlood retainCount]);


BloodType * tempBlood2 = [[BloodType alloc]init];
//NSLog(@"Retain count is: %@", [tempBlood retainCount]);

tempBlood2.allele1 = self.allele2;
tempBlood2.allele2 = otherBlood.allele2;
NSLog(@"%@", tempBlood2);
[array addObject: tempBlood2];


BloodType * tempBlood3 = [[BloodType alloc]init];
tempBlood3.allele1 = self.allele1;
tempBlood3.allele2 = otherBlood.allele2;
NSLog(@"%@", tempBlood3);
[array addObject: tempBlood3];

BloodType * tempBlood4 = [[BloodType alloc]init];
tempBlood4.allele1 = self.allele2;
tempBlood4.allele2 = otherBlood.allele1;
NSLog(@"%@", tempBlood4);
[array addObject: tempBlood4];
NSLog(@"Retain count of tempBlood4 is: %i", [tempBlood4 retainCount]);


NSLog(@"Retain count of tempBlood4 is: %i", [tempBlood4 retainCount]);




//NSLog(@"Retain count is: %i", [array retainCount]);

for (BloodType * blood in array) //Fast enumeration
{
NSLog(@"%@", blood);
}

/*

NSArray * array2 = [NSArray arrayWithObjects: @"I", @"am", @"Theo", nil];

if ([array2 writeToFile: @"/Users/theopavlakou/Desktop/blood.txt" atomically: YES] == NO)
{NSLog(@"Not Successful");}

if ([array writeToFile: @"/Users/theopavlakou/Desktop/blood.txt" atomically: YES] == NO)
{NSLog(@"Not Successful");}//Why not working? Because can't print descriptions, needs NSStrings.
*/

/* [tempBlood release];
[tempBlood2 release];
[tempBlood3 release];
[tempBlood4 release];
*/

NSArray * arr2 = [NSArray arrayWithArray: array];
[arr2 writeToFile: @"/Users/theopavlakou/Desktop/blood.txt" atomically: YES];

return array;
}


Thank you so much by the way :)
 
The block of code sending release to tempBlood1, tempBlood2, tempBlood3 and tempBlood4 is still commented out.

Also you haven't sent release any of the arrays you've created.

A pattern that you can use is to autorelease at creation. For example, instead of this:
Code:
BloodType *tempBlood1 = [[BloodType alloc] init];
// later in the same method
[tempBlood1 release];
Do this instead:
Code:
BloodType *tempBlood1 = [[[BloodType alloc] init] autorelease];
 
Thank you

Hey man, yeah I know that it is commented out, you see every so often I get an EXC_BAD_ACCESS error, but not every time and I am not sure why, whether or not I release the memory (although I did release the second array), at the end, the array that I return, am I meant to somehow release that too? Also, any ideas why I am getting the error? I think maybe it's due to memory management elsewhere as well.
Thanks
 
Also

Hey also, how does memory management look in here? Thanks man. If I'm being a pain tell me and I will stop :p



-(NSString *) alleleAsString
{

NSMutableString * a1 = [[NSMutableString alloc]init];
NSMutableString * a2 = [[NSMutableString alloc]init];


switch (self.allele1) {
case O:
[a1 appendString: @"O"];
break;
case A:
[a1 appendString: @"A"];
break;
case B:
[a1 appendString: @"B"];
break;
default:[a1 appendString: @"***There was an error!***"];
break;
}



switch (self.allele2) {
case O:
[a2 appendString: @"O"];
break;
case A:
[a2 appendString: @"A"];
break;
case B:
[a2 appendString: @"B"];
break;
default:[a2 appendString: @"***There was an error!***"];
break;
}




//[a1 autorelease];
//[a2 autorelease];

NSString * retString = [NSString stringWithFormat: @"blood genotype is %@ %@", a1 , a2];
[retString autorelease];


[a1 release];
[a2 release];

return (retString);







}

Thanks again :)
 
Hey also, how does memory management look in here? Thanks man. If I'm being a pain tell me and I will stop :p

[...]
Code:
	NSString * retString = [NSString stringWithFormat: @"blood genotype is %@ %@", a1  , a2];
	[retString autorelease];

[...]

Thanks again :)

No need to autorelease retString. You created it using a convenience method so you don't really 'own' it.
 
Thanks again

Hey man, yeah, just realised that, and also the arrays in bloodType.m also don't need to be released either. Thanks a lot man. If we were in the same country I would take you out for a drink :p
 
Now look at the method "makeBabyWith" and at the rules for object ownership. Does the method name start with "copy" or "create"? So should the object that the method returns be autoreleased or not?
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.