2009-04-02 30 views
10

Tôi là nhà phát triển Microsoft lâu năm và tôi mới phát triển iPhone bằng cách sử dụng XCode. Vì vậy, tôi đang đọc một cuốn sách và trải qua các ví dụ cố gắng tự dạy mình cách viết một ứng dụng iPhone bằng cách sử dụng Objective-C. Tất cả đã tốt cho đến nay, tuy nhiên, một lần trong một thời gian tôi chạy vào thông báo chung 'objc_exception_throw' khi chạy. Khi điều này xảy ra, nguồn gốc của ngoại lệ này rất khó tìm. Sau một số thử và sai, tôi tìm thấy câu trả lời của mình. Một trong các tham số đã sai chính tả.Gỡ lỗi ngoại lệ được ném vào Mục tiêu C và XCode

Như bạn có thể thấy bên dưới, tôi đã viết sai thông số 'otherButtonTitles' bằng cách bỏ nút 't' thứ hai.

UIAlertView *alert = [[UIAlertView alloc] 
         initWithTitle:@"Date and Time Selected" 
         message:message 
         delegate:nil 
         cancelButtonTitle:@"Cancel" 
         otherButonTitles:nil]; 

Lý do khiến tôi mất nhiều thời gian để tìm mã được tạo thành công. Đây có phải là hành vi bình thường đối với trình biên dịch Objective-C không? Tôi đang sử dụng để có xây dựng thất bại trong trình biên dịch. NET khi tôi thực hiện một lỗi cú pháp phổ biến như thế này. Có một thiết lập trình biên dịch tôi có thể thay đổi để làm cho xây dựng thất bại khi tôi thực hiện những sai lầm?

+1

Một người có nhiều đại diện hơn tôi nên chỉnh sửa tiêu đề của nội dung này thành "Debugging and prevent 'objc_exception_throw'". –

Trả lời

25

Trước hết, mở ~/.gdbinit (đó là các tập tin gọi là .gdbinit trong thư mục chính của bạn - có, bắt đầu với một dấu chấm) và đặt điều này trong nó:

fb -[NSException raise] 
fb objc_exception_throw 
fb malloc_error_break 

Điều đó sẽ khởi GDB với ba breakpoint mặc định , khi chúng xảy ra, GDB sẽ tạm dừng ứng dụng của bạn và hiển thị cho bạn dấu vết ngăn xếp. Điều này được tích hợp rất tốt với Xcode để bạn có thể đi qua mã của mình một cách độc đáo bằng cách nhấp vào các phần tử theo dõi ngăn xếp ngay sau khi một ngoại lệ xảy ra ở đâu đó hoặc một malloc không thành công.

Sau đó, mở Get Info bảng trên dự án của bạn (hoặc chọn dự án của bạn (mục hàng đầu trong Groups & Files) và nhấn cmd-i), đi đến Build tab và thiết lập của Base SDK-Device - iPhone OS [someversion] dự án của bạn. Cuộn xuống phía dưới và tìm phần GCC 4.0 - Warnings. Ở đó; bật nhiều cảnh báo khi bạn cảm thấy thoải mái, nhưng hãy đảm bảo bật Treat Warnings as Errors (điều này tương đương với GCC_TREAT_WARNINGS_AS_ERRORS). Cá nhân, tôi có nó thiết lập như sau:

GCC Warning Build Settings http://lhunath.lyndir.com/stuff/gcc_warnings.png

Bây giờ bạn sẽ nhận được cảnh báo trình biên dịch cho hầu hết mọi thứ bạn có thể làm sai trong mã và trình biên dịch sẽ không cho phép bạn chạy các mã cho đến khi bạn khắc phục chúng. Khi mọi thứ vượt qua mũi của trình biên dịch, bạn sẽ có thể dễ dàng tìm ra vấn đề với GDB phá vỡ tại một vị trí thuận tiện.

Bạn cũng nên xem xét NSZombie*. Đây là những biến môi trường rất tiện lợi cho việc phá vỡ phân bổ bộ nhớ xấu hoặc các tình huống truy cập. Ví dụ; wih NSZombieEnabled không có gì thực sự được phát hành; trên dealloc nó sẽ bị ghi đè với _NSZombie và bạn nên thử truy cập lại bộ nhớ dealloced này (dereferencing một con trỏ dealloced) bạn sẽ nhận được một cái gì đó để phá vỡ trong GDB, thay vì cuộc gọi đi qua như bình thường, chỉ được phát hành ngẫu nhiên dữ liệu (tất nhiên, không phải là những gì bạn muốn). Để biết thêm thông tin về điều này, hãy xem http://www.cocoadev.com/index.pl?NSZombieEnabled.

+0

LƯU Ý: Để có cảnh báo "Cảnh báo GCC 4.0" xuất hiện trong cài đặt của bạn (như được hiển thị ở trên), bạn phải có SDK cơ sở và SDK hoạt động được đặt thành Thiết bị chứ không phải Trình mô phỏng. – rtemp

+0

Ngoài ra, khi bạn bật "Xử lý cảnh báo dưới dạng lỗi", bạn sẽ vẫn thấy các cảnh báo như trước nhưng bạn sẽ nhận được 1 lỗi hơi gây nhầm lẫn "Command /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/gcc-4.0 không thành công mã thoát 1 ". Lỗi này sẽ biến mất khi tất cả các cảnh báo bị xóa. – rtemp

8

Thông số sai chính tả thường dẫn đến "Cảnh báo: đối tượng như vậy và không phản hồi với bộ chọn x" màu vàng ở dòng được đề cập. Tôi tin rằng điều này được bật theo mặc định, vì tôi không phải thay đổi bất kỳ cài đặt trình biên dịch nào để xem chúng.

Ngoài ra, khi tôi gặp phải một ngoại lệ còn tự do, đôi khi có lợi cho thả vào gdb console (nên đưa ra khi bạn thực hiện ứng dụng của bạn) và gõ như sau để có được vết lùi cho tất cả các chủ đề:

TAA BT

+0

"taa bt" là viết tắt của "thread áp dụng tất cả các backtrace" và chỉ cần in một backtrace cho tất cả các chủ đề –

1

Lý do không phải là lỗi biên dịch, bởi vì nó hoàn toàn hợp lệ để gửi tin nhắn không được biết tại thời gian biên dịch cho bất kỳ đối tượng nào (và bất kỳ đối tượng nào cũng có thể được định cấu hình để xử lý thư). Tất cả các cuộc gọi phương thức thực sự là các tin nhắn được gửi tới các đối tượng.

Nói chung, nếu bạn thấy bất kỳ cảnh báo nào, bạn nên giải quyết chúng, vì trong hầu hết các trường hợp, chúng có thể dẫn đến sự cố (như bạn đã thấy). Các khía cạnh gây hiểu lầm là ở đây là nếu bạn biên dịch một tập tin một lần và nó chỉ có cảnh báo, nếu bạn biên dịch các lớp khác mà không làm thay đổi lớp có cảnh báo, cảnh báo sẽ không hiển thị trong các thông điệp trình biên dịch. Vì vậy, tất cả bây giờ và sau đó bạn có thể muốn "làm sạch tất cả các mục tiêu" và xây dựng một lần nữa để đảm bảo rằng bạn đã không bỏ lỡ bất kỳ cảnh báo.

2

Những gì bạn đã làm không phải là lỗi biên dịch, bởi vì thời gian chạy Objective-C kiểm tra thời gian chạy nếu đối tượng có thể trả lời thư bạn gửi đến.

tôi khuyên bạn nên thêm thiết với mục tiêu, dự án của bạn build này:

GCC_TREAT_WARNINGS_AS_ERRORS = YES 
9

Luôn sử dụng cài đặt -Werror GCC (GCC_TREAT_WARNINGS_AS_ERRORS = YES). Bạn không bao giờ nên có cảnh báo trong mã của bạn và đây là một ví dụ mà cảnh báo là một lỗi nghiêm trọng.

Ngoài ra, nếu bạn nhận được objc_exception_throw, hãy chuyển sang bảng điều khiển (Command-shift-R) và tìm địa chỉ số "thấp" đầu tiên.

2009-04-01 13:25:43.385 CrashExample[41720:20b] Stack: (
    2528013804, 
    2478503148, 
    2528036920, 
    2528053460, 
    2358032430, 
    11076, 
    11880, 
    816174880, 
    345098340, 
    145973440, 
    816174880, 
) 

Trong trường hợp này, nó sẽ là "11076". Vì vậy, hãy nhập vào bảng điều khiển:

info line *11076 

Điều đó sẽ cho bạn biết dòng trong mã của bạn, nơi ngoại lệ được ném.

+0

Đó là một số lời khuyên tuyệt vời - một điều khác để thêm là đặt một breakpoint toàn cầu về "objc_exception_throw", sẽ tự động phá vỡ khi mã của bạn làm điều gì đó ném một ngoại lệ. –

Các vấn đề liên quan