Objective-C: Assertion vs. Exception vs. Error


79

Trong Ca cao, khi nào tôi nên sử dụng NSAssert, NSException, NSError?

Đây là những gì tôi đã nghĩ:

NSAssert - Khi tạo bất kỳ chương trình khách nào được sử dụng cho lợi ích của chính lập trình viên để kiểm tra kỹ các quy tắc, quy ước, giả định hoặc điều kiện trước và điều kiện sau?

NSException - Khi tạo thư viện của bên thứ ba vì lợi ích của các lập trình viên khác sử dụng thư viện, để họ biết ngay khi đầu vào không hợp lệ?

NSError - Khi giao tiếp với hệ thống bên ngoài để lấy dữ liệu như tệp, cơ sở dữ liệu hoặc dịch vụ web không được đảm bảo cung cấp cho tôi kết quả?

Câu trả lời:


103

Một NSAssert sẽ ném một ngoại lệ khi nó không thành công. Vì vậy, NSAssert có cách viết ngắn gọn và dễ dàng và kiểm tra bất kỳ giả định nào bạn đã đặt ra trong mã của mình. Nó không phải là (theo ý kiến ​​của tôi) một sự thay thế cho các trường hợp ngoại lệ, chỉ là một lối tắt. Nếu một xác nhận không thành công thì mã của bạn đã xảy ra lỗi nghiêm trọng và chương trình không nên tiếp tục.

Một điều cần lưu ý là NSAssert sẽ không được biên dịch thành mã của bạn trong bản dựng phát hành, vì vậy điều này thường được sử dụng để kiểm tra sự tỉnh táo trong quá trình phát triển. Tôi thực sự có xu hướng sử dụng macro xác nhận tùy chỉnh luôn hoạt động.

Những lần bạn muốn NSException@throw của riêng mình là khi bạn chắc chắn muốn nó trong một bản phát hành và trong những thứ như thư viện / giao diện công cộng khi một số đối số không hợp lệ hoặc bạn bị gọi không chính xác. Lưu ý rằng nó không thực sự là thông lệ tiêu chuẩn đối với một ngoại lệ và tiếp tục chạy ứng dụng của bạn. Nếu bạn thử điều này với một số thư viện tiêu chuẩn của Apple (ví dụ Core Data), điều tồi tệ có thể xảy ra. Tương tự như một xác nhận, nếu một ngoại lệ được ném ra, ứng dụng thường sẽ kết thúc khá nhanh vì điều đó có nghĩa là có lỗi lập trình ở đâu đó.@catch

NSErrors nên được sử dụng trong các thư viện / giao diện của bạn cho các lỗi không phải là lỗi lập trình và có thể được khôi phục từ đó. Bạn có thể cung cấp thông tin / mã lỗi cho người gọi và họ có thể xử lý lỗi sạch sẽ, thông báo cho người dùng nếu thích hợp và tiếp tục thực hiện. Điều này thường xảy ra đối với những thứ như lỗi Không tìm thấy tệp hoặc một số lỗi không nghiêm trọng khác.


15
Nói một cách mạnh mẽ hơn, không nên sử dụng NSException để chỉ ra lỗi có thể khôi phục được.
bbum

28
Nói cách khác: lớp Lỗi NSException == Java của Obj-C và lớp Ngoại lệ của NSError == Java của obj-C. Hoan hô vì sự nhất quán trong các điều khoản!
Tustin2121

2
Trên thực tế, NSAssert sẽ được biên dịch thành mã của bạn nếu bạn không thêm NS_BLOCK_ASSERTIONS trong các tệp tiền tố được biên dịch trước của mình. Đọc câu trả lời bên dưới (chỉ nhận được 50 để khen ngợi ngay bây giờ :)
likid1412

3

Quy ước trong Cocoa là một ngoại lệ chỉ ra lỗi của lập trình viên. Rất nhiều mã, bao gồm cả mã khung, không được thiết kế để hoạt động bình thường sau khi một ngoại lệ được ném ra.

Bất kỳ loại lỗi nào có thể khôi phục được biểu thị bằng một NSError. Ngoài ra còn có một hệ thống để trình bày NSErrors cho người dùng. Như bạn nói, điều này chủ yếu hữu ích cho các tài nguyên bên ngoài có thể thất bại.

Về mặt khái niệm, một khẳng định là một tuyên bố mà một vị từ cho trước luôn đánh giá là true; nếu không, chương trình bị hỏng. Mặc dù hành vi của nó có thể được sửa đổi, nhưng NSAsserttheo mặc định , họ là một cách thuận tiện để ném NSInternalInconsistencyExceptions (với tùy chọn tắt chúng trong các bản dựng phát hành).


2

Chỉnh sửa: Trong Xcode 4.2, xác nhận bị tắt theo mặc định cho các bản phát hành,

Bây giờ NSAssert sẽ không được biên dịch thành mã của bạn trong một bản phát hành , nhưng bạn có thể thay đổi nó trong cài đặt bản dựng


@Mike Weller, Có một câu trả lời sai trong câu trả lời của bạn.

Một điều cần lưu ý là NSAssert sẽ không được biên dịch thành mã của bạn trong bản dựng phát hành , vì vậy điều này thường được sử dụng để kiểm tra sự tỉnh táo trong quá trình phát triển.

Trên thực tế, NSAssert sẽ được biên dịch thành mã của bạn nếu bạn không thêm NS_BLOCK_ASSERTIONSvào các tệp tiền tố được biên dịch trước của mình.

Trong Ghi chú kỹ thuật TN2190, chúng ta có thể tìm thấy:

Các macro như NDEBUG để tắt C khẳng định hoặc NS_BLOCK_ASSERTIONS để tắt NSAssert của Foundation rất quan trọng để chỉ định cho các tệp tiền tố được biên dịch trước của bạn

Hoặc bạn có thể đọc phần này: Làm thế nào để biết NSAssert có bị vô hiệu hóa trong các bản phát hành hay không?


1

Nói chung, các ngoại lệ được sử dụng để báo hiệu lỗi của lập trình viên - chúng là những điều không nên xảy ra. Lỗi được sử dụng để báo hiệu các điều kiện lỗi có thể xuất hiện trong hoạt động bình thường của chương trình - về cơ bản, lỗi người dùng hoặc các điều kiện bên ngoài cần đúng nhưng có thể không đúng. Vì vậy, cố gắng xóa một số phần tử bị khóa trong tài liệu có thể là một lỗi và cố gắng tải xuống tệp mà không có kết nối Internet sẽ là một lỗi, nhưng cố gắng truy cập phần tử không hợp lệ trong một bộ sưu tập sẽ là một ngoại lệ.

Các xác nhận thường được sử dụng trong thử nghiệm và AFAIK không được sử dụng làm cơ chế xử lý lỗi chung như các cơ chế khác.


Các xác nhận có thể được sử dụng để thực thi các bất biến. Ví dụ, NSParameterAssert(someParam != nil);sẽ thực thi bất biến mà tham số được chỉ định không được bằng nil.
Lily Ballard

@Kevin Ballard: Các xác nhận thường được xác định trong các bản dựng phát hành, hoặc ít nhất chúng cũng được tôi kiểm tra lần cuối, vì vậy giống như tôi đã nói chúng không phải là một cơ chế xử lý lỗi chung.
Chuck

1
Chúng có thể được, nhưng chúng không bị bỏ qua theo mặc định. Bạn phải thay đổi cài đặt xây dựng để có được hành vi đó.
Lily Ballard
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.