UIViewController purgeMemoryForReason: сбой в iOS 5 - PullRequest
17 голосов
/ 08 января 2012

Так что я довольно часто видел этот сбой в Crashlytics, как на iPad, так и на iPad 2, работающем под iOS 5. Похоже, что это вызвано предупреждением памяти, но трассировка стека не ссылается ни на какой код моего приложения, только платформы iOS:

0    libobjc.A.dylib    objc_msgSend + 15
1    UIKit          -[UIViewController purgeMemoryForReason:] + 64
2    Foundation     __57-[NSNotificationCenter addObserver: selector: name: object:]_block_invoke_0 + 18
3    CoreFoundation     ___CFXNotificationPost_block_invoke_0 + 70
4    CoreFoundation     _CFXNotificationPost + 1406
5    Foundation     -[NSNotificationCenter postNotificationName: object: userInfo:] + 66
6    Foundation     -[NSNotificationCenter postNotificationName: object:] + 30
7    UIKit          -[UIApplication _performMemoryWarning] + 80
8    UIKit          -[UIApplication _receivedMemoryNotification] + 174
9    libdispatch.dylib  _dispatch_source_invoke + 516
10   libdispatch.dylib  _dispatch_queue_invoke + 50
11   libdispatch.dylib  _dispatch_main_queue_callback_4CF + 156
12   CoreFoundation     __CFRunLoopRun + 1268
13   CoreFoundation     CFRunLoopRunSpecific + 300
14   CoreFoundation     CFRunLoopRunInMode + 104
15   GraphicsServices   GSEventRunModal + 156
16   UIKit          UIApplicationMain + 1090
17   500px iOS      main.m line 12

Я погуглил высоко и низко, но не могу найти никаких решений для этого.Похоже, это вызвано чрезмерным выпуском экземпляра UIViewController, но я использую ARC, поэтому я не понимаю, как это могло быть.

Я в растерянности, как дажеподойти к этому.Я даже не могу сказать, какой подкласс UIViewController вызывает проблему.Я пытался воспроизвести проблему в симуляторе и на устройстве, но не могу найти причину.Кто-нибудь видел что-нибудь подобное или есть предложения о том, как подойти к воспроизведению проблемы?

Ответы [ 2 ]

17 голосов
/ 08 января 2012

Я думаю, что решил проблему. Я думал об этом, и проблема не в выгрузке представления UIViewController, а в публикации фактического предупреждения о нехватке памяти. В моем коде есть несколько случаев, когда я звоню [[NSNotificationCenter defaultCenter] removeObserver:self]. Это нормально в методе dealloc, но в viewDidUnload методах было два таких случая.

Я заметил это, когда моя точка останова в didReceiveMemory одного из контроллеров UIViewController не была достигнута. Код в viewDidUnload также отменял регистрацию self от других системных уведомлений, а подробные здесь .

Я не собираюсь отмечать это как принятый ответ, пока не проверю, что сбои прекращаются с новым обновлением.

ОБНОВЛЕНИЕ: С помощью Crashlytics я проверил, что проблема была исправлена!

8 голосов
/ 19 сентября 2013

Я заметил точно такую ​​же трассировку стека в сбоях, о которых сообщает HockeyApp для устройств, работающих на iOS 5.

I никогда не вызывал [[NSNotificationCenter defaultCenter] removeObserver:self], кроме как в dealloc, так что это не могло бытьпричина сбоя.

Вот как я смог воспроизвести сбой: из MasterViewController я нажимаю DetailViewController, а затем выскакиваю его, нажимая кнопку возврата.Наконец, я запускаю предупреждение памяти и происходит сбой (только на iOS 5).

Оказывается, что экземпляр DetailViewController не освобождается после извлечения из-за цикла сохранения при использовании SVPullToRefresh:

@implementation DetailViewController

- (void) viewDidLoad
{
    [super viewDidLoad];

    [self.scrollView addPullToRefreshWithActionHandler:^{
        [self refresh];
    }];
}

@end

Так как DetailViewController не выпущен, он все еще зарегистрирован для предупреждений памяти и вот что происходит:

frame #0: 0x0004d61b MyApp`-[DetailViewController dealloc](self=0x089a5150, _cmd=0x024d2738) + 27 at DetailViewController.m:103
frame #1: 0x0227ae3d libobjc.A.dylib`_objc_rootRelease + 47
frame #2: 0x0227ae00 libobjc.A.dylib`objc_release + 48
frame #3: 0x0227c047 libobjc.A.dylib`objc_storeStrong + 39
frame #4: 0x0004e44c MyApp`__destroy_helper_block_ + 44 at DetailViewController.m:157
frame #5: 0x029b555d libsystem_sim_blocks.dylib`_Block_release + 166
frame #6: 0x0227ae00 libobjc.A.dylib`objc_release + 48
frame #7: 0x0227c047 libobjc.A.dylib`objc_storeStrong + 39
frame #8: 0x00084c8d MyApp`-[SVPullToRefreshView .cxx_destruct](self=0x08bf3af0, _cmd=0x00000001) + 525 at UIScrollView+SVPullToRefresh.m:121
frame #9: 0x0226630d libobjc.A.dylib`object_cxxDestructFromClass + 104
frame #10: 0x02270fde libobjc.A.dylib`objc_destructInstance + 38
frame #11: 0x02271015 libobjc.A.dylib`object_dispose + 20
frame #12: 0x0247a9a1 CoreFoundation`-[NSObject dealloc] + 97
frame #13: 0x00a8cdc7 UIKit`-[UIView dealloc] + 748
frame #14: 0x0227ae3d libobjc.A.dylib`_objc_rootRelease + 47
frame #15: 0x00a90b73 UIKit`-[UIView(Hierarchy) removeFromSuperview] + 194
frame #16: 0x00a8cc10 UIKit`-[UIView dealloc] + 309
frame #17: 0x00a9d6ff UIKit`-[UIScrollView dealloc] + 405
frame #18: 0x013ab36c Foundation`NSKVODeallocate + 105
frame #19: 0x0227ae3d libobjc.A.dylib`_objc_rootRelease + 47
frame #20: 0x00b21c12 UIKit`-[UIViewController setView:] + 447
frame #21: 0x00b21885 UIKit`-[UIViewController unloadViewForced:] + 117
frame #22: 0x00b2180b UIKit`-[UIViewController unloadViewIfReloadable] + 41
frame #23: 0x00b256ff UIKit`-[UIViewController purgeMemoryForReason:] + 75
frame #24: 0x00b2563b UIKit`-[UIViewController didReceiveMemoryWarning] + 41
frame #25: 0x00b2560d UIKit`-[UIViewController _didReceiveMemoryWarning:] + 33
frame #26: 0x0141ca29 Foundation`__57-[NSNotificationCenter addObserver:selector:name:object:]_block_invoke_0 + 40
frame #27: 0x02443855 CoreFoundation`___CFXNotificationPost_block_invoke_0 + 85
frame #28: 0x02443778 CoreFoundation`_CFXNotificationPost + 1976
frame #29: 0x0136119a Foundation`-[NSNotificationCenter postNotificationName:object:userInfo:] + 98
frame #30: 0x0136db03 Foundation`-[NSNotificationCenter postNotificationName:object:] + 55
frame #31: 0x00a64cf4 UIKit`-[UIApplication _performMemoryWarning] + 91
frame #32: 0x00a64e00 UIKit`-[UIApplication _receivedMemoryNotification] + 180
frame #33: 0x00a64f98 UIKit`__block_global_0 + 36
frame #34: 0x029f1450 libdispatch.dylib`_dispatch_source_invoke + 719
frame #35: 0x029edcc4 libdispatch.dylib`_dispatch_queue_invoke + 66
frame #36: 0x029ee4cf libdispatch.dylib`_dispatch_main_queue_callback_4CF + 295
frame #37: 0x023af803 CoreFoundation`__CFRunLoopRun + 2003
frame #38: 0x023aed84 CoreFoundation`CFRunLoopRunSpecific + 212
frame #39: 0x023aec9b CoreFoundation`CFRunLoopRunInMode + 123
frame #40: 0x038d07d8 GraphicsServices`GSEventRunModal + 190
frame #41: 0x038d088a GraphicsServices`GSEventRun + 103
frame #42: 0x00a5a626 UIKit`UIApplicationMain + 1163
frame #43: 0x00002b82 MyApp`main(argc=1, argv=0xbffff318) + 178 at main.m:15

Или на английском языке: экземпляр SVPullToRefreshView выпущен какрезультат выгрузки вида.Поскольку экземпляр SVPullToRefreshView является последним объектом, который содержит ссылку на DetailViewController, он освобождается, а затем освобождается.Но purgeMemoryForReason: все еще делал (то есть обращался к переменным экземпляра) с помощью только что освобожденного контроллера представления, что приводило к сбою.

После диагностики решение было очень простым: просто избегайте цикла сохраненияво-первых.

@implementation DetailViewController

- (void) viewDidLoad
{
    [super viewDidLoad];

    __typeof__(self) __weak weakSelf = self;
    [self.scrollView addPullToRefreshWithActionHandler:^{
        [weakSelf refresh];
    }];
}

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