开发者

Objective-C copy an NSArray properly?

My iPhone app keeps crashing, and I've narrowed it down to this one line over the past bloody week:

NSArray *fetchResults = [managedObjectContext executeFetchRequest:request error:&error];

I'm getting the right result from the above, but the app crashes after accessing it (EXC_BAD_ACCESS). How do I just copy the contents of fetchResults so that I can play around with it?

I've tried

NSArray *retVal = [[NSArray alloc] initWithArray:fetchResults];
NSArray *retVal = [[NSArray alloc] initWithArray:[fetchResults copy]];
NSArray *retVal开发者_运维知识库 = [[NSArray alloc] initWithArray:[fetchResults retain]];

but the only thing that doesn't crash the app is

NSArray *retVal = [[NSArray alloc] initWithArray:nil];

Could someone help me out? I'm thinking I'll need a lesson in Obj-C memory management.

EDIT: Here's a more complete example of code that crashes:

NSArray *fetchResults = [managedObjectContext executeFetchRequest:request error:&error];
[request release];
NSMutableArray *retVal = [NSMutableArray arrayWithCapacity:0];
for(Job *job in fetchResults){
    //NSLog(@"dev: %@",job.lastmod_device);
    NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
                            [job.jobkey copy], @"entitykey",
                            [NSNumber numberWithInt:[job.lastmod_device timeIntervalSince1970]], @"job_lastmod_device",
                            [NSNumber numberWithInt:[job.lastmod_server timeIntervalSince1970]], @"job_lastmod_server",
                            [NSNumber numberWithInt:[job.customer.lastmod_device timeIntervalSince1970]], @"customer_lastmod_device",
                            [NSNumber numberWithInt:[job.customer.lastmod_server timeIntervalSince1970]], @"customer_lastmod_server",
                            [NSNumber numberWithInt:[job.productionschedule_lastmod_device timeIntervalSince1970]], @"productionschedule_lastmod_device",
                            [NSNumber numberWithInt:[job.productionschedule_lastmod_server timeIntervalSince1970]], @"productionschedule_lastmod_server", nil];
    //NSLog(@"dict: %@", dict);
    [retVal addObject:dict];
}
return retVal;

And the code that calls this method:

NSArray *arr2 = [self retrieveJobs];

(that's it; I never even use the variable)

EDIT 2: Even just iterating over the fetched result with an empty for loop and doing nothing else with the fetchResults object makes the app crash. How is this even possible?


You are thrashing; of these lines of code...

NSArray *retVal = [[NSArray alloc] initWithArray:fetchResults];
NSArray *retVal = [[NSArray alloc] initWithArray:[fetchResults copy]];
NSArray *retVal = [[NSArray alloc] initWithArray:[fetchResults retain]];

The latter two are simple leaks. The first is one way of making a copy, but retVal = [fetchResults copy]; is a better way to make a copy.

But, of course, you don't need a copy at all. That isn't the problem. You go on to say that the only thing that doesn't crash is an empty result set.

That indicates one of two things; either your result set is corrupt (unlikely) or you are accessing the result set incorrectly (likely).

The "thrashing" is that you have asked a question about a crash without including either the backtrace of the crash or the location of the crash. Add those and you'll likely get an answer in short order.

(And don't take offense at "thrashing" -- we all do it. Even after 20+ years of Objective-C, I still have to facepalm, step back, and think things through to get away from thrashing.)


NSArray *retVal = [fetchResults retain] should keep everything around for you. It doesn't make a copy, but I expect that's not really what you're trying to do. Your first attempt there should make a copy. They're all prone to leaking if you're not careful though (your second example leaks guaranteed). Are you sure you're not doing something else in the program that makes this part of the code fail?

Here are some options for doing a real copy if that's what you want:

NSArray *retVal = [fetchResults copy];
NSArray *retVal = [[NSArray alloc] initWithArray:fetchResults];

Both of those return retained arrays to you.


Are you sure the fetch request is returning data? According to the documentation:

An array of objects that meet the criteria specified by request fetched from the receiver and from the persistent stores associated with the receiver’s persistent store coordinator. If an error occurs, returns nil. If no objects match the criteria specified by request, returns an empty array.

Also, could you show the code where you access the array? Is it in the same method where you're executing the fetch request?


NSArray *retVal = [[NSArray alloc] initWithArray:fetchResults];
NSArray *retVal = [[NSArray alloc] initWithArray:[fetchResults copy]];
NSArray *retVal = [[NSArray alloc] initWithArray:[fetchResults retain]];

Are you sure that fetchResults contains result? Because there may be a chance that "fetchResults" object itself released and pointing to some garbage location. That is why you are getting crash. Check and inform whether fetchResults is a valid object or not.


To get a true copy without a reference to the original, you will need to do a DEEP copy. One method is to archive the array and unarchive it back into an NSArray.

Collections with IOS

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜