简体   繁体   English

Objective-C正确复制NSArray?

[英]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: 我的iPhone应用程序一直在崩溃,在过去的血腥周中我将它缩小到这一行:

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 ). 我从上面得到了正确的结果,但是应用程序在访问后崩溃了( EXC_BAD_ACCESS )。 How do I just copy the contents of fetchResults so that I can play around with it? 如何复制fetchResults的内容以便我可以使用它?

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. 我想我需要上Obj-C内存管理课程。

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. 编辑2:即使只使用空的for循环迭代获取的结果,并且对fetchResults对象不执行任何操作fetchResults导致应用程序崩溃。 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]; 第一种是制作副本的方法,但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.) (并且不要冒犯“捶打” - 我们都这样做。即使经过20多年的Objective-C,我仍然需要面对,退后一步,思考一切,以摆脱颠簸。)

NSArray *retVal = [fetchResults retain] should keep everything around for you. NSArray *retVal = [fetchResults retain]应该为你保留一切。 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. 如果发生错误,则返回nil。 If no objects match the criteria specified by request, returns an empty array. 如果没有对象符合request指定的条件,则返回一个空数组。

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? 你确定fetchResults包含结果吗? Because there may be a chance that "fetchResults" object itself released and pointing to some garbage location . 因为“fetchResults”对象本身可能会释放并指向某个垃圾位置 That is why you are getting crash. 这就是你崩溃的原因。 Check and inform whether fetchResults is a valid object or not. 检查并通知fetchResults是否为有效对象。

To get a true copy without a reference to the original, you will need to do a DEEP copy. 要获得没有引用原件的真实副本,您需要执行DEEP副本。 One method is to archive the array and unarchive it back into an NSArray. 一种方法是归档数组并将其解压缩回NSArray。

Collections with IOS 与IOS的集合

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM