2015-02-16 2 views
-1

Я застрял на нем уже более недели и, по-видимому, никто не сообщил об этой проблеме ранее в stackoverflow. Пожалуйста, внимательно прочитайте мое описание, прежде чем обращаться ко мне с другими сообщениями, потому что я прочитал их все, и никто из них не получил моего ответа.- [__ NSDictionaryI isNSString__]: сообщение отправлено на освобожденный экземпляр

У меня есть NSDictionary, содержащий NSNumber и NSArray из NSStrings, причем оба ключа являются NSStrings.

Теперь NSDictionary WriteToFile падает с ошибкой: - [NSDictionaryI isNSString]: сообщение, отправленное высвобождены например

WriteToFile вызывается метод класса, как, например:

@implementation AppDataStore 

+ (void) saveData:(NSDictionary*)dataDictionary { 

    NSArray *directories = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 
    NSString *documents = [directories firstObject]; 
    NSString *appDataFilePath = [documents stringByAppendingPathComponent:@"AppDataStore.plist"]; 
    [dataDictionary writeToFile:appDataFilePath atomically:YES]; 
} 

Следует отметить, что я Я передаю метод NSMutableDictionary для этого метода, но это не проблема, потому что он записывает другие значения ключа NSMutableDictionaries просто отлично, но не содержит тот, который содержит NSArray. Даже когда я вынимаю элемент NSNumber, поэтому словарь содержит только NSArray, writeToFile все равно выдает ту же ошибку. Сбой как на симуляторе, так и на iPhone.

Что происходит ?!

EDIT 1 (в ответ на вопрос Адама):

стека не проследить вплоть до прямо перед аварией:

Stack trace : (
    0 MedList        0x00009b39 +[AppDataStore saveData:] + 217 
    1 MedList        0x0000811d -[ViewController tableView:didSelectRowAtIndexPath:] + 1101 
    2 UIKit        0x010c894c -[UITableView _selectRowAtIndexPath:animated:scrollPosition:notifyDelegate:] + 1559 
    3 UIKit        0x010c8af7 -[UITableView _userSelectRowAtPendingSelectionIndexPath:] + 285 
    4 UIKit        0x010cddf3 __38-[UITableView touchesEnded:withEvent:]_block_invoke + 43 
    5 UIKit        0x00fe20ce ___afterCACommitHandler_block_invoke + 15 
    6 UIKit        0x00fe2079 _applyBlockToCFArrayCopiedToStack + 415 
    7 UIKit        0x00fe1e8e _afterCACommitHandler + 545 
    8 CoreFoundation      0x00b289de __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 30 
    9 CoreFoundation      0x00b28920 __CFRunLoopDoObservers + 400 
    10 CoreFoundation      0x00b1e35a __CFRunLoopRun + 1226 
    11 CoreFoundation      0x00b1dbcb CFRunLoopRunSpecific + 443 
    12 CoreFoundation      0x00b1d9fb CFRunLoopRunInMode + 123 
    13 GraphicsServices     0x03efd24f GSEventRunModal + 192 
    14 GraphicsServices     0x03efd08c GSEventRun + 104 
    15 UIKit        0x00fb88b6 UIApplicationMain + 1526 
    16 MedList        0x0000681d main + 141 
    17 libdyld.dylib      0x02f6bac9 start + 1 
    18 ???         0x00000001 0x0 + 1 
) 
2015-02-16 21:39:37.762 MedList[14029:496685] *** -[__NSDictionaryI isNSString__]: message sent to deallocated instance 0x7974e910 

EDIT 2: Я сделал еще несколько тестов. NSDictionary внутри моего NSArray получает освобождение ПЕРЕД вызовом метода класса (до writeToFile) и только AFTER didSelectRowAtIndexPath. Почему выбор строки таблицы автоматически освобождает словарь, содержащийся внутри массива? Это странное поведение. Есть предположения?

+4

У вас есть трассировки стека? – AdamPro13

+1

Мы уверены, что это NSDictionary, который терпит неудачу, так как это класс, который появляется в сообщении. (Он мог быть освобожден как нечто другое, а затем перераспределено, поскольку NSDicitonary затем снова освобождается, но это кажется маловероятным.) Однако мы не знаем, является ли он самым внешним словарем или «внутренним», внутри 'dataDictionary'. Если можно было бы остановиться, когда возникла ошибка, и поместите отладчик в стек стека 'saveData' и сделайте' po dataDictionary', тогда он должен сбросить объект, и у вас будет ключ к вопросу о том, исчезло ли оно или что-то в нем , –

+0

Я признаю, что раньше такого отладки не делал. Можете ли вы опубликовать пару скриншотов, которые показывают, как это сделать? Я провел мое исследование по po (print-object), до сих пор безрезультатно. –

ответ

0

Прежде всего, спасибо вам всем, особенно Duncan и Hot Licks за то, что помогли мне сузить ошибку и, наконец, поймать ее. Итак, я заметил, что NSDictionary внутри моего NSArray был освобожден, как только я вышел из области viewDidLoad, что означает, что я действительно не обладал этим NSDictionary, хотя я и думал, что сделал.

Проблема была вызвана тем, что я создавал этот NSDictionary другим вызовом метода класса, который я наивно назвал init, поэтому скрывал мое фактическое несоблюдение возвращенного NSDictionary, обманывая меня мыслью, что я владел им, просто позвонив init.

Проблема решена после того, как я переименовал init в «create», а затем правильно назначил инициализацию моего NSDictionary в моем представленииDidLoad перед вызовом create. Словарь теперь сохранен, и ошибка исчезла.

Для тех, кто сталкивается с подобными проблемами, я очень рекомендую этот ресурс, который является то, что на самом деле заставило меня наконец-то найти ошибку:

https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.pdf

0

Теория озгура - это достойное предположение о том, что происходит. Другая возможность заключается в том, что в массиве есть что-то фанки, которое вы пишете. writeToFile:atomically: и его родственники требуют, чтобы весь «графический объект», который вы пишете, должен быть объектом «список свойств» (небольшой список классов: NSString, NSData, NSDate, NSNumber, NSArray или NSDictionary). Любой объект, который не является ни одним из контейнеров или подконтейнеров в графе объектов, может привести к сбою записи.

Однако, я привык видеть только то, что файл не написан, а не авария. У вас может быть зомби где-то в вашем массиве, хотя это гораздо менее вероятно при ARC, чем в ручном подсчете ссылок. Вам пришлось бы добавить объект __unsafe_unretained к массиву или контейнеру, находящемуся внутри массива.

+0

Что такое теория Озгура? Или кто Озгур, я должен спросить? Дункан, я заверяю вас, что весь графический объект является списком свойств. Все контейнеры и подконтейнеры являются либо NSStrings, либо NSDictionaries из NSStrings, за исключением того, что я упоминал NSNumber, который является значением другого ключа NSString корневого NSDictionary. Приложение полностью сбой с ошибкой, о которой я упоминал. Первоначальный крах был неудачным крахом доступа, поэтому я включил зомби, чтобы я мог поймать виновника, который, кажется, является сообщением, отправленным на освобожденный экземпляр, когда writeToFile проверяет, что NSDictionary является списком свойств. –

+1

ozgur - еще один ответчик на ваш вопрос. См. Его ответ ниже. Похоже, что один из объектов в вашем объектном графе - зомби. Вам нужно выяснить, какой из них и как туда добраться. Найдите свой проект для unsafe_unretained и отследите их. Или напишите код, который проходит ваш графа объектов, регистрируя класс каждого объекта в нем. Он сработает на оскорбительном объекте. –

+0

Спасибо Дункан. Ответ Озгура должен был быть удален или каким-то образом скрыт от моего взгляда. Я никогда не видел ответа на его имя и все еще не вижу. В любом случае, в отношении моего вопроса, я записал весь графический объект с кучей вложенных циклов. Когда он попадает в единственный словарь, содержащийся в моем nsarray внутри корневого nsdictionary, [dic class] падает с «сообщением, отправленным на освобожденный экземпляр». Почему мой словарь освобождается? !!! Он создается в методе класса, используя правильную инициализацию alloc, а также словарь root. Что происходит? –

Смежные вопросы