2012-01-07 36 views
17

Vì vậy, tôi đã nhìn thấy vụ tai nạn này khá thường xuyên trong Crashlytics, cả trên iPad và iPad 2, chạy iOS 5. Dường như nó gây ra bởi cảnh báo bộ nhớ, nhưng ngăn xếp ngăn xếp không ' t tham chiếu bất kỳ mã ứng dụng nào của tôi, chỉ các khung công tác iOS:UIViewController purgeMemoryForReason: Crashing trên iOS 5

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 

Tôi đã googled cao và thấp nhưng không thể tìm thấy bất kỳ giải pháp nào cho điều này. Có vẻ như điều này là do việc phát hành một bản sao UIViewController quá mức, nhưng tôi đang sử dụng ARC, vì vậy tôi không thấy nó có thể xảy ra như thế nào.

Tôi đang mất phương pháp tiếp cận điều này. Tôi thậm chí không thể cho biết lớp con UIViewController nào gây ra vấn đề. Tôi đã thử tái tạo vấn đề trong trình mô phỏng và trên thiết bị, nhưng tôi không thể tìm thấy nguyên nhân gây ra lỗi đó. Có ai nhìn thấy bất cứ điều gì như thế này hoặc có đề xuất về cách tiếp cận tái tạo vấn đề?

+2

Thú vị. Thông thường, bước tiếp theo trên stack sẽ là một lệnh unloadViewIfReloadable trên viewController đó. Như chúng ta thấy một vụ tai nạn bây giờ, điều này có nghĩa là phương pháp này thậm chí đã không đạt được hoặc chúng tôi đã nhận được đằng sau bước đó. Đối với thứ hai, kiểm tra triển khai phương thức viewDidUnload của bạn. Đó sẽ là bước tiếp theo tôi sẽ xem xét. Như một khuyến nghị tiêu chuẩn, kích hoạt zombie và kích hoạt cảnh báo bộ nhớ trên trình mô phỏng. – Till

+0

Tôi sẽ quay lại và quay lại với bạn. Cảm ơn! –

Trả lời

17

Tôi nghĩ rằng tôi đã giải quyết được vấn đề. Tôi đã suy nghĩ về nó, và vấn đề không phải là dỡ bỏ của UIViewController xem, đó là việc đăng thông báo cảnh báo bộ nhớ thấp thực tế. Có một số trường hợp trong mã của tôi nơi tôi gọi [[NSNotificationCenter defaultCenter] removeObserver:self]. Điều này là tốt trong phương pháp dealloc, nhưng có hai trường hợp này trong phương thức viewDidUnload.

Tôi nhận thấy điều này khi điểm ngắt của tôi trong didReceiveMemory của một trong những UIViewController không bị ảnh hưởng. Mã trong số viewDidUnload cũng không hủy đăng ký self từ các thông báo hệ thống khác, như chi tiết here.

Tôi sẽ không đánh dấu đây là câu trả lời được chấp nhận cho đến khi tôi xác minh rằng các sự cố dừng lại với bản cập nhật mới.

CẬP NHẬT: Tôi đã xác minh với Crashlytics rằng sự cố đã được khắc phục!

+2

Vâng, quy tắc thông báo vàng quan sát: chỉ xóa người quan sát đối với những thông báo bạn đã đăng ký. Tôi đã đọc về nó một thời gian trước đây, nhưng chưa bao giờ gặp hậu quả rõ ràng như vậy. Rất vui vì bạn đã khắc phục sự cố của mình. – iHunter

+0

@AshFurrow xóa tự khỏi các thông báo đó trên viewDidUnload _only_ nếu bạn đang đăng ký những người trong viewDidLoad. – Till

+0

@Tất cả vấn đề là, UIViewController dường như đang đăng ký thông báo khi khởi tạo mà tôi chưa đăng ký trong viewDidUnload. Tôi đã thay đổi removeObserver của mình: thành removeObserver: name: object: do đó tôi chỉ * không đăng ký các thông báo cụ thể. –

8

tôi nhận thấy cùng stack trace chính xác đến sự cố báo cáo của HockeyApp cho các thiết bị chạy trên iOS 5.

tôi never called[[NSNotificationCenter defaultCenter] removeObserver:self] trừ dealloc bên trong, vì vậy đây không thể là nguyên nhân của vụ tai nạn.

Đây là cách tôi có thể tạo lại sự cố: từ MasterViewController Tôi đẩy DetailViewController, sau đó bật bằng cách nhấn vào nút quay lại. Cuối cùng, tôi kích hoạt cảnh báo bộ nhớ và sự cố xảy ra (chỉ trên iOS 5).

Nó chỉ ra rằng trường hợp DetailViewController không được giải phóng sau khi được popped vì một chu kỳ duy trì khi sử dụng SVPullToRefresh:

@implementation DetailViewController 

- (void) viewDidLoad 
{ 
    [super viewDidLoad]; 

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

@end 

Kể từ khi DetailViewController không được giải phóng nó vẫn đăng ký cho các thông báo cảnh báo bộ nhớ và đây là những gì xảy ra:

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 

Hoặc bằng tiếng Anh: phiên bản SVPullToRefreshView được phát hành do kết quả của lượt xem được tải. Kể từ khi cá thể SVPullToRefreshView là đối tượng cuối cùng để giữ tham chiếu đến DetailViewController, nó được giải phóng, sau đó bị phân phối lại. Nhưng purgeMemoryForReason: vẫn còn làm những việc (tức là truy cập các biến mẫu) với bộ điều khiển chế độ xem vừa được deallocated, do đó sự cố.

Sau khi chẩn đoán giải pháp rất đơn giản: chỉ cần tránh chu kỳ giữ lại ở vị trí đầu tiên.

@implementation DetailViewController 

- (void) viewDidLoad 
{ 
    [super viewDidLoad]; 

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

@end 
+0

Một lỗi ở đây là purgeMemoryForReason không giữ lại bản thân trước khi nó thực hiện công việc của nó và sau đó tự giải phóng sau khi nó kết thúc. Một điều khác nữa là VC không có kết nối mạnh mẽ với quan điểm của nó, dựa vào việc đặt hàng giả định cho một sự rách rưới thành công của hệ thống phân cấp khung nhìn. –