iOS - Passing a NSMutableArray via method return - iphone

How would one pass a NSMutableArray via method return.
I have it passing the array "spaces" so an array of 10 objects passes the 10 blocks but none of the information contained in those objects.
Thanks in advance
Edit: Basically I created another class that contains path information because my controller was getting a bit cluttered. So this new class I want call the "create" method which returns an NSMutableArray. The array is created fine in the path class but when the return statement fires it only passes the spaces and not the values or even a pointer.
currently it's
return path;
I've tried
return &path;
and that fails epically.
Edit2: Here is the issue I'm having unfortunately.
Still crashing
calling
newNode = [newNode copy];
causes a crash

- (NSMutableArray *) mutableFloobizwits {
NSMutableArray *array = [NSMutableArray array];
for (NSInteger i = 0; i < TheAnswerToTheUltimateQuestion; ++i) {
void(^MyBlock)(void) = ^{
NSLog(#"captured i: %ld", i);
};
MyBlock = [MyBlock copy]; //move the block from off the stack and onto the heap
[array addObject:[Floobizwit floobizwithWithBlock:MyBlock]];
[MyBlock release]; //the Floobizwit should've -retained the block, so we release it
}
return array;
}

I would set up your other class that returns the array of path objects as follows:
#implementation PathFactory
- (NSMutableArray*) create
{
// In your PathFactory object you create an array and make it autorelease so
// it becomes the callers responsibility to free the memory
NSMutableArray * pathArray = [[[NSMutableArray alloc] init] autorelease];
// Create a bunch of PathObject objects and add them to the mutable array
// also set these to autorelease because the NSMutableArray will retain objects
// added to the collection (ie It is the NSMutableArray's responsibility to ensure
// the objects remain allocated).
for (int i = 0; i < numberOfPaths; i++)
[pathArray addObject:[[[PathObject alloc] init] autorelease]];
// Just return the pointer to the NSMutableArray. The caller will need to
// call the retain message on the pointer it gets back (see next)
return pathArray;
}
#end
So in your caller code:
// create a tempory PathFactory (autorelease will make sure it is cleaned up when we
// are finished here)
PathFactory * newPathFactory = [[[PathFactory alloc] init] autorelease];
// grab the new array of Path objects and retain the memory. _newPathArray
// is a member of this class that you will need to release later.
_newPathArray = [[newPathFactory create] retain];

Related

EXC_BAD_ACCESS error in during fetching data from custome objects

I had stored custom objects data in Array. I am fetching data from Array of custom objects in a function. when I am calling function for first time it is working good but When I am calling it again and again I am getting EXC_BAD_ACCESS.
Here is function details.
-(void) facebookDisplayFunction:(int)atIndex {
FacebookWallData *wall = (FacebookWallData *)[facebook_wallDataArray objectAtIndex:atIndex];
NSString *friendID= wall.actor_id;
NSString *linkFetch= wall.permalink;
NSString* postID=wall.postId;
NSNumber *countNumber;
NSString *friendName=#"";
NSString* profileThumImage=#"";
for(int i=0; i< [facebook_LikesArray count];i++) {
FacebookLikes* countValues=[[FacebookLikes alloc]init];
countValues=[facebook_LikesArray objectAtIndex:i];
// NSLog(#" postId_wall %# LikePostId = %#",postID,countValues.PostID);
if([postID isEqualToString:countValues.PostID]) {
countNumber=countValues.Count;
if(countNumber>0)
friendID=countValues.Friends;
[countValues release];
break;
}
[countValues release];
}
for(int i=0;i< [facebook_FreindsArray count];i++) {
FacebookFreinds* friendsRecord=[[FacebookFreinds alloc]init];
friendsRecord=[facebook_FreindsArray objectAtIndex:i];
if([friendID isEqualToString:friendsRecord.UID]) {
friendName=friendsRecord.name;
profileThumImage=friendsRecord.pic_smal;
[friendsRecord release];
break;
}
[friendsRecord release];
}
// Adding values in table //
[imageData addObject:#"facebook.png"];
[tableList addObject:wall.messages];
[profileUserName addObject:friendName];
[linksOfFacebookData addObject:linkFetch];
[RetweetAndLikeData addObject:#"5"];
[favedProfileThumb addObject:profileThumImage];
[twitterPostID addObject:#""];
[eachPostUID addObject:friendID];
[wall release];
}
And here I am calling function.
[self facebookDisplayFunction:0];
[self facebookDisplayFunction:0]; // EXC_BAD_ACCESS error here.
Why are you allocating an object like this FacebookLikes* countValues=[[FacebookLikes alloc]init] and then assigning to this same variable the instance inside the array with this code countValues=[facebook_LikesArray objectAtIndex:i] and later on you release it with this [countValues release]? You don't know what you are doing.
Try changing this:
FacebookLikes* countValues=[[FacebookLikes alloc]init];
countValues=[facebook_LikesArray objectAtIndex:i];
to this
FacebookLikes* countValues = [facebook_LikesArray objectAtIndex:i];
and remove all occurrences of [countValues release]. Do the same for the friendsRecord in the second for-loop. Also, what is the [wall release]? Remove it!
You should not allocate any of these objects because you are actually obtaining them from that array, and not creating a new instance. That just creates a leak in your code. You should not release any of these objects because they are retained by the array, and it is responsible for releasing them whenever they are removed from the array or after the array is destroyed/deallocated. Please, rtfm
If you get the error on the line:
[self facebookDisplayFunction:0];
it seems to me that most likely the object pointed by self has been deallocated. So, the problem would not be in facebookDisplayFunction...
Could you review how you create the object pointed by self, or post the code if you need more help?

IPhone - copyWithZone leak

Testing my app on the device it returns a leak whe i call the copy of a custom object ande i can't understand why.
this is the call:
NSMutableArray *arr = [[NSMutableArray alloc] initWithCapacity:5];
for (SinglePart *sp in [copyFrom partList]) {
[arr addObject:[sp copy]];
}
self.partList = arr;
[arr release];
this is the method:
- (id)copyWithZone:(NSZone *)zone {
SinglePart *copy = [[[self class] allocWithZone:zone] initWithSinglePart:self];
[copy loadImage];
return copy;
}
this is the method that is called by copyWithZone:
- (id)initWithSinglePart:(SinglePart *)copyFrom {
if (self = [super init]) {
self.imagePath = [copyFrom.imagePath copy];
self.color = [UIColor colorWithCGColor:copyFrom.color.CGColor];
self.hasOwnColor = copyFrom.hasOwnColor;
self.blendingMode = copyFrom.blendingMode;
}
return self;
}
copy returns a new object with retain count 1. Meaning you need to release the new object, which you are not doing.
NSMutableArray *arr = [[NSMutableArray alloc] initWithCapacity:5];
for (SinglePart *sp in [copyFrom partList]) {
SingPart *theCopy = [sp copy];
[arr addObject:theCopy];
[theCopy release];
}
self.partList = arr;
[arr release];
Even your custom copyWithZone: method inits an object, but does not autorelease it, which is the expected behavior of a copy method. Copy must be balanced just like a retain or init, meaning you must balance it with release at some point.
Lastly, your initWithSinglePart: method leaks the imagePath as well. In this case if you declare the imagePath property as copy instead of retain then you don't need to do this manually at all. Then you simply assign the value and let the property setter do it for you.
// Header
#property (copy) NSString *imagePath;
// Now this will do the copy for you
self.imagePath = copyFrom.imagePath;
Also, is the property imagePath defined with retain or copy semantics?
If so you need to add an autorelease here:
self.imagePath = [[copyFrom.imagePath copy] autorelease];
because the default setter will retain/copy it too.
So, you either need to autorelease, or omit the "self." to bypass the default setter.
You are making a copy of sp and then adding it to the array. The array then retains the object so your retain count is now 2.
In the end you release arr, thus making the retain count of it's items 1.
You should either add another release to the sp objects, or not use copy.
Try this:
self.partList = [NSMutableArray arrayWithCapacity:5];
for (SinglePart *sp in [copyFrom partList]) {
[arr addObject:sp];
}

NSMutableArray of Objects misbehaves

I hope someone understands what happens to my NSMutableArray.
I read records a, b, c, d from a database, load the fields into an object an add the object to an array. To do this I read the records into an instance of that object (tmpEvent) and add the Object to the target array (NSMutableArray myArray).
the code looks like:
for (condition) {
tmpEvent.field1 = [NSString stringWithUTF8String:(char*)sqlite3_column_text(stmt, 0)];
tmpEvent.field2 = [NSString stringWithUTF8String:(char*)sqlite3_column_text(stmt, 1)];
tmpEvent.field3 = [NSString stringWithUTF8String:(char*)sqlite3_column_text(stmt, 2)];
NSLog(#"myArray: adding %#", tmpEvent.field1);
[myArray addObject:tmpEvent];
}
The NSLog shows
myArray: adding a
myArray: adding b
myArray: adding c
myArray: adding d
Subsequent I enumerate the array (this can be in the same or a different method):
for (myObject *records in myArray) {
NSLog(#"iEvents value %#", records.field1);
}
The NSLog now shows:
myArray value d
myArray value d
myArray value d
myArray value d
a mystery .... ??? any thoughts?
You need to allocate a new "iEvent" for each event. tmpEvent.field1 is pointing to the same place in memory for each subsequent add, therefore you are modifying the object that is already stored in the array. NSArray does not make a new copy of the object, just stores its pointer/address.
One fix:
[myArray addObject:[tmpEvent copy]];
This assumes the members of the iEvent class conform to NSCopy.
Another is to allocate a new tmpEvent for each event that you want to store.
Question: But does this mean that when I free my array agein I need to enumerate through and "manually" release the objects again?
Answer: You should send the object a release after adding it to the array as the array sends it a retain. When you dispose of the array, all objects are sent a release so you don't have to. See below...
Give the alloc option a try as conforming to NSCopying requires you to alloc an object anyway:
for (condition) {
tmpEvent = [[TmpEvent alloc] init]; // Or however it is initialized
tmpEvent.field1 = [NSString stringWithUTF8String:(char*)sqlite3_column_text(stmt, 0)];
tmpEvent.field2 = ...
[myArray addObject:tmpEvent];
// NSArray retains objects that you add.
[tmpEvent release];
}
---- To Conform to NSCopy ---
1. Class must inherit from NSCopying
#interface TmpEvent : NSObject ...
Implement - (id) copyWithZone:(NSZone *) zone
(id)copyWithZone:(NSZone *)zone {
TmpEvent *copyOfMyself = [[TmpEvent alloc] init];
copyOfMyself.field1 = [self.field1 copy];
.... etc.
return copyOfMyself;
}

Please help me in solving retain mystery in iPhone?

Please consider the following code:
//CallerClass.h
#interface CallerClass : UITableViewController {
NSMutableArray *dataArray;
}
#property(nonatomic,retain) NSMutableArray *dataArray;
-(void) setData;
//CallerClass.m
#implementation CallerClass
#synthesize dataArray;
-(id)initWithStyle:(UITableViewStyle)style {
if (self = [super initWithStyle:style]) {
[self setData];
}
return self;
}
-(void) setData
{
dataArray = [CalledClass getData];
[dataArray release];
}
//CalledClass.h
#interface CalledClass : NSObject {
}
+(NSMutableArray*) getData;
//CalledClass.m
#implementation CalledClass
+(NSMutableArray*) getData
{
NSMutableArray* tempArray = [[NSMutableArray alloc] init];
return tempArray;
}
I want to know what is the retain count for dataArray that is tempArray. Is it getting released. I dont want to use autorelease as I dont know till what time period I will need it. So I want to release it on my own. When I allocated tempArray, its retain count becomes 1. But when I assign it to instance variable dataArray whose property is retain, Is the retain count for that array becomes 2 or it stays 1. Like on releasing dataArray will it release memory.
You've set up your property to retain the value, but then you're not using the accessor methods but set the instance variable directly instead:
dataArray = [CalledClass getData];
won't manage the retain count for you. You have to use:
self.dataArray = [CalledClass getData];
Also, in your CalledClass, I'd change the getData method to this:
+(NSMutableArray*) getData
{
NSMutableArray* tempArray = [[NSMutableArray alloc] init];
return [tempArray autorelease];
}
Normally I'd expect to get an autoreleased object back from a method with a name like this.
setData: should then be something like:
-(void) setData
{
self.dataArray = [CalledClass getData];
}
or you could get rid of it entirely and just directly do
self.dataArray = [CalledClass getData]
in initWithStyle:.
By calling self.dataArray instead of assigning directly to the instance variable, your dataArray property will take care of retaining and releasing the object (because you specified "retain" in the property declaration)
dataArray = [CalledClass getData];
That doesn't invoke the retain attribute of the property. That's just plain old assignment iirc. [self setDataArray:[CalledClass getData]] would give a reference count of 2 on your array.

Cocoa Touch: Accessor method + memory needs clarification

Please consider a problem constructing an array and returning it to a parent object. Please have a look at my code and comments below.
My question is: Why does method THREE work while methods ONE and TWO do not?
// ****************************
// Master.m
// ****************************
// Simply declare array and call accessor
NSMutableArray * allElementTypes;
allElementTypes = [ElementObject badElements];
// ****************************
// ElementObject.m
// ****************************
// Doesn't work (EXE_BAD_ACCESS)
+ (NSMutableArray*) badElements {
NSMutableArray * array = [[NSMutableArray alloc] initWithObjects:#"crab", #"poison", #"snake"];
return array;
}
// Doesn't work (EXE_BAD_ACCESS)
+ (NSMutableArray*) badElements {
return [NSMutableArray arrayWithObjects:#"crab", #"poison", #"snake"];
}
// WORKS
+ (NSMutableArray*) badElements {
NSMutableArray * array = [[NSMutableArray alloc] init];
[array addObject:#"crab"];
[array addObject:#"poison"];
[array addObject:#"snake"];
return array; // TODO: release this memory
}
-arrayWithObjects: or -initWithObjects takes a nil terminated, variable length, list of arguments.
You wrote:
[NSMutableArray arrayWithObjects:#"crab", #"poison", #"snake"];
where you should have written:
[NSMutableArray arrayWithObjects:#"crab", #"poison", #"snake", nil];