0

My App Crashed [translate]

App của bạn đang chạy ngon lành, bỗng đâu ngày trời đẹp và app bị crash. Việc đầu tiên của bạn là đừng hoảng sợ, bắt đầu tìm hiểu nguyên nhân để fix lỗi này 1 cách triệt để, bạn không thể trông chờ vào may rủi đc. Trình tự đầu tiên là bạn cần là lần theo cách file bị lỗi và từ đâu đi đến thao tác đó. Đầu tiên bạn hãy down project sau về. NóNó đương nhiên là 1 project lỗi. Khi bạn mở project với xcode nó sẽ show ra các warning khi compiler. Chạy app và bạn sẽ nhìn thấy điều đnag chờ. alt

Nó đã bị crash. Cơ bản nóc 2 loại crash. SIGABRT (còn gọi là EXC_CRASH) và EXC_BAD_ACCESS (mà cũng có thể thể hiện dưới các tên SIGBUS hoặc SIGSEGV). Nếu là SIGABRT thì khá tốt bởi bạn có thể control đc lỗi đễ dàng. Lỗi code bạn viết không support đc hết các trường hợp. EXC_BAD_ACCESS là loại khó khăn hơn, rất khó để tìm ra lỗi, trước đây thường là liên quan đến bộ nhớ còn bây giờ nó hay xảy ra khi truy cập đến các đối tượng đã bị huỷ.

Project này đang bị SIGABRT  crash. Lỗi này thường được xcode chỉ rõ ra trong cửa sổ outputProblems[14465:f803] -[UINavigationController setList:]: unrecognized selector sent to
instance 0x6a33840
Problems[14465:f803] *** Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: '-[UINavigationController setList:]: unrecognized selector sent to instance 0x6a33840'
*** First throw call stack:
(0x13ba052 0x154bd0a 0x13bbced 0x1320f00 0x1320ce2 0x29ef 0xf9d6 0x108a6 0x1f743
0x201f8 0x13aa9 0x12a4fa9 0x138e1c5 0x12f3022 0x12f190a 0x12f0db4 0x12f0ccb 0x102a7
0x11a9b 0x2792 0x2705)
terminate called throwing an exception

Điều quan trọng là bạn tìm hiểu để giải mã các thông báo lỗi bởi vì chúng chứa những đầu mối quan trọng như những gì đang xảy ra sai. Ở đây, một phần thú vị là:

 [UINavigationController setList:]: unrecognized selector sent to instance 0x6a33840

Các thông báo lỗi "unrecognized selector sent to instance XXX" có nghĩa là các ứng dụng đang cố gắng gọi một method đó không tồn tại.

Biết được lí do crash là tốt nhưng khóa học đầu tiên của hành động này là để tìm ra nơi trong code để xảy ra lỗi này. Bạn cần tìm ra tên file và số lượng các dòng có thể gây lỗi. Bạn có thể làm điều này bằng cách sử dụng các call stack.

alt

Hiện nay xcode đã highligh hàm Main() trong file main.m là gốc dễ của vấn đề. Nhưng nó ko đưa cho bạn biết gì cả, bạn cần tìm sâu hơn.

Để xem chi tiết của các call stack, kéo thanh trượt ở dưới cùng của Debug Navigator tất cả các con đường bên phải. Điều đó sẽ hiển thị các call stack đầy đủ tại thời điểm crash.

alt

Các chức năng ở phía dưới, start (), được gọi là đầu tiên. Một nơi nào đó trong thực thi của nó, nó được gọi là chức năng ở trên nó, main (). Đó là điểm khởi đầu của các ứng dụng, và nó sẽ luôn luôn được gần bên dưới. main () lần lượt được gọi là UIApplicationMain (). Đó là những dòng mà mũi tên màu xanh lá cây (ở đầu dòng đánh dấu trên cửa sổ bên phải trong Xcode) đang trỏ tới trong cửa sổ soạn thảo. Sẽ tiếp tục lên stack, UIApplicationMain () được gọi là method _run trên đối tượng UIApplication, mà gọi là CFRunLoopRunInMode (), mà gọi là CFRunLoopRunSpecific (), và như vậy, tất cả các con đường lên đến __pthread_kill.

alt

The Exception Breakpoint

Vì vậy, làm thế nào để bạn tìm thấy những dòng trong mã mà thực hiện các vụ tai nạn ứng dụng? Vâng, bất cứ khi nào bạn nhận được một stacktrace như thế này, một ngoại lệ được ném ra bởi các ứng dụng. (Bạn có thể cho biết, vì một trong những chức năng trong các cuộc gọi stack được đặt tên objc_exception_rethrow.) Một ngoại lệ xảy ra khi chương trình được bắt gặp đang làm một cái gì đó nó không nên làm. Hậu quả của ngoại lệ này những gì bạn đang tìm kiếm tại bây giờ là: ứng dụng làm gì sai, các ngoại lệ đã được ném ra, và Xcode cho bạn thấy kết quả. Lý tưởng nhất, bạn muốn thấy chính xác nơi mà ngoại lệ được ném ra May mắn là bạn có thể tạm dừng chương trình tại các thời điểm khi thêm 1 điểm break point. Để thiết lập break poin bạn vần cần chuyển sang tab beakpoint navigation.

alt

alt alt ngoài ra bạn có thể click trực tiếp vào bên cạnh line mà bạn muốn đặt debug, bọn này chém gió phần này dài dòng quá 😄.

alt

Rõ ràng, thủ phạm là dòng này trong các ứng dụng của appdelegate:

viewController.list = [NSArray arrayWithObjects:@"One", @"Two"];

Hãy xem thông báo lỗi một lần nữa:

[UINavigationController setList:]: unrecognized selector sent to instance 0x6d4ed20

nhìn ở đây bạn thấy rằng ko có hàm setlist để sửa lỗi này bạn đơn giản chỉ cần làm nhưu sau:

  • (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
	UINavigationController *navController = (UINavigationController *)self.window.rootViewController;
	MainViewController *viewController = (MainViewController *)navController.topViewController;
	viewController.list = [NSArray arrayWithObjects:@"One", @"Two"];
	return YES;
}

Lưu ý: Bất cứ khi nào bạn nhận được một lỗi “unrecognized selector sent to instance XXX” bạn cần ktra các method với tên tương ứng. alt

Your First Memory Error-

Chạy các ứng dụng một lần nữa. Rất tiếc, nó bị treo tại cùng một dòng, bây giờ chỉ với một lỗi EXC_BAD_ACCESS. Điều đó có nghĩa là các ứng dụng có một vấn đề quản lý bộ nhớ. alt

lỗi liên quan đến bộ nhớ thường khó xác định, tuy rằng giờ chúng ta dùng arc nhưng nhiều chỗ vẫn cần quản lí cho tốt, nếu ko ứng dụng rất dễ tèo. Khi 1 chỗ bị đầy bộ nhớ nó sẽ báo ở các nơi khác nhau. nhiều khi không liên quan gì đến chỗ gây đày bôj nhớ cả.

Vụ tai nạn đặc biệt này, tuy nhiên, rất dễ dàng để sửa chữa. Nếu bạn nhìn vào trình soạn thảo mã nguồn, Xcode đã được cảnh báo về dòng này. alt

Ở đây khj khởi tạo 1 array bạn cần kết thúc bằng nil. Nhưng bạn đã ko làm như vậy. Sửa lại đoạn code sẽ như sau:

viewController.list = [NSArray arrayWithObjects:@"One", @"Two", nil];

“This class is not key value coding-compliant”

Chạy app lại 1 lần nữa để thấy các lỗi khác trong dự án. ban thấy gì? nó lại bị treo train main. alt

Nếu bạn xem xét thông qua các tên phương pháp từ trên đi xuống, có một số thứ đang diễn ra với NSObject và Key-Value. Dưới đây là một cuộc gọi đến [UIRuntimeOutletConnection connection]. Tôi không có ý tưởng đó là gì, nhưng có vẻ như nó có cái gì để làm với các kết nối outlets.

Để xem các thông báo lỗi đầy đủ, bấm vào nút "Continue Program Execution" trong thanh công cụ gỡ lỗi: alt Bạn có thể cần phải bấm vào more, nhưng sau đó bạn sẽ nhận được thông báo lỗi:

  Problems[14961:f803] *** Terminating app due to uncaught exception 'NSUnknownKeyException',
reason: '[<MainViewController 0x6b3f590> setValue:forUndefinedKey:]: this class is not
key value coding-compliant for the key button.'
*** First throw call stack:
(0x13ba052 0x154bd0a 0x13b9f11 0x9b1032 0x922f7b 0x922eeb 0x93dd60 0x23091a 0x13bbe1a
0x1325821 0x22f46e 0xd6e2c 0xd73a9 0xd75cb 0xd6c1c 0xfd56d 0xe7d47 0xfe441 0xfe45d
0xfe4f9 0x3ed65 0x3edac 0xfbe6 0x108a6 0x1f743 0x201f8 0x13aa9 0x12a4fa9 0x138e1c5
0x12f3022 0x12f190a 0x12f0db4 0x12f0ccb 0x102a7 0x11a9b 0x2872 0x27e5)
terminate called throwing an exception

Messing with Memory Nào bạn chạy ứng dụng và click vào nút "Tap me", nó sẽ đưa ra 1 thông báo lỗi về EXC_BAD_ACCESS . cđoạn gât ra lỗi là đoạn code sau:

NSLog("You tapped on: %s", sender);

Đôi khi những sai lầm này có thể mất một thời điểm hoặc hai để đăng ký trong tâm trí của bạn, nhưng một lần nữa Xcode cho vay một bàn tay giúp đỡ - chỉ cần nhấp vào hình tam giác màu vàng để xem những gì là sai: alt khj có các warning màu vàng như vậy. Nghĩa là code bạn viết chưa tối ưu, có thể ko gây ra lỗi trực tiếp nhưng tiềm tàng có khả năng gây ra crash.

Hãy xem những gì các cảnh báo mới là:

alt

%s chỉ là dành cho 1 đoạn chuỗi, nhưng sender ở đây là 1 giá trị kiểu object. vd như ở đây là crash.

Bạn chỉ cần sửa như sau:

NSLog(@"You tapped on: %@", sender);

Phần sau sẽ là giới thiêu thêm về các kiểu debug. phần này chỉ tới đây thôi nhé:d


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.