Objective-C правильно скопировать NSArray? - PullRequest
5 голосов
/ 26 февраля 2010

Мое приложение для iPhone продолжает падать, и за последнюю кровавую неделю я сократил его до одной строчки:

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

Я получаю правильный результат из вышеперечисленного, но приложение падает после обращения к нему (EXC_BAD_ACCESS). Как мне просто скопировать содержимое fetchResults, чтобы я мог поиграть с ним?

Я пробовал

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

но единственное, что не приводит к сбою приложения, это

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

Может ли кто-нибудь мне помочь? Думаю, мне понадобится урок по управлению памятью в Obj-C.

EDIT: Вот более полный пример сбоя кода:

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;

И код, который вызывает этот метод:

NSArray *arr2 = [self retrieveJobs];

(вот и все; я даже не использую переменную)

РЕДАКТИРОВАТЬ 2: Даже просто перебирая полученный результат с пустым циклом for и ничего не делая с объектом fetchResults, происходит сбой приложения. Как это вообще возможно?

Ответы [ 5 ]

19 голосов
/ 26 февраля 2010

Ты бьешься; из этих строк кода ...

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

Последние два - простые утечки. Первый способ - сделать копию, но retVal = [fetchResults copy]; - лучший способ сделать копию.

Но, конечно, вам вообще не нужна копия . Это не проблема. Вы продолжаете говорить, что единственное, что не падает, это пустой набор результатов.

Это указывает на одну из двух вещей; Либо ваш набор результатов поврежден (маловероятно), либо вы неверно (вероятно) обращаетесь к нему.

«Побитость» заключается в том, что вы задали вопрос о сбое, не указав ни его след, ни место сбоя. Добавьте их, и вы, скорее всего, получите ответ в короткие сроки.

(И не обижайтесь на «избиение» - мы все это делаем. Даже после 20 с лишним лет Objective-C, мне все еще приходится сталкиваться лицом к лицу, отступать и обдумывать вещи, чтобы избежать побоев. )

2 голосов
/ 26 февраля 2010

NSArray *retVal = [fetchResults retain] должен держать все вокруг вас. Это не делает копию, но я ожидаю, что это не совсем то, что вы пытаетесь сделать. Ваша первая попытка должна сделать копию. Они все подвержены утечке, если вы не будете осторожны (ваш второй пример утечки гарантирован). Вы уверены, что не делаете в программе что-то еще, что приводит к сбою этой части кода?

Вот несколько вариантов создания реальной копии, если вы этого хотите:

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

Оба из этих возвращенных сохраненных массивов вам.

1 голос
/ 26 февраля 2010
NSArray *retVal = [[NSArray alloc] initWithArray:fetchResults];
NSArray *retVal = [[NSArray alloc] initWithArray:[fetchResults copy]];
NSArray *retVal = [[NSArray alloc] initWithArray:[fetchResults retain]];

Вы уверены, что fetchResults содержит результат? Поскольку может существовать вероятность того, что сам объект "fetchResults" был освобожден и указывает на какое-то место для мусора . Вот почему вы получаете сбой. Проверьте и сообщите, является ли fetchResults действительным объектом или нет.

1 голос
/ 26 февраля 2010

Вы уверены, что запрос на выборку возвращает данные? Согласно документации:

Массив объектов, которые соответствуют критериям, указанным в запросе, полученном от получателя и из постоянных хранилищ, связанных с координатором постоянного хранилища получателя. Если возникает ошибка, возвращает ноль. Если ни один объект не соответствует критериям, указанным в запросе, возвращает пустой массив.

Кроме того, не могли бы вы показать код доступа к массиву? Это тот же метод, где вы выполняете запрос на выборку?

0 голосов
/ 17 июня 2011

Чтобы получить истинную копию без ссылки на оригинал, вам нужно будет сделать ГЛУБОКУЮ копию. Один из способов - заархивировать массив и разархивировать его обратно в NSArray.

Коллекции с IOS

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...