2009-07-13 27 views
8

tôi đang làm việc trên porting một codebase Java để Cocoa/Objective-C để sử dụng trên máy tính để bàn đang Mac OS X. Java có nhiềunhiều các phương pháp với những ngoại lệ kiểm tra như:Khi chuyển mã Java sang ObjC, cách tốt nhất để thể hiện các ngoại lệ đã kiểm tra?

double asNumber() throws FooException { 
    ... 
} 

gì cách tốt nhất để đại diện cho chúng trong Objective-C là gì? Ngoại lệ hoặc lỗi tham số?

- (CGFloat)asNumber { 
    ... // possibly [FooException raise:format:]; 
} 

hoặc

- (CGFloat)asNumberError:(NSError **)outError { 
    ... 
} 

Tôi có cảm giác rằng ngoài sai sót nói chung là giải pháp tốt hơn cho Objective-C, nhưng khi bạn có thể thấy ... rất nhiều phương pháp như một trong những sẽ ở trên trông khá lúng túng. Và một lần nữa, có lô hàng trong số này.

Dĩ nhiên cần lưu ý rằng vì đây là những kiểm tra trường hợp ngoại lệ trong Java, tôi sẽ cần phải thêm một trong hai @try khối hoặc if (*outError) {...} kiểm tra bất cứ nơi nào các phương pháp này được gọi là (nhiều nơi).

Tôi nhớ lại rằng khi nhập @try khối đã từng đắt tiền trong Mục tiêu-C, giá rẻ ở 64 bit hoặc SL hoặc một số ENV mới khác (không nhớ chính xác). Tôi hoàn toàn không lo lắng về khả năng tương thích ngược, vì vậy tôi là chắc chắn là sẵn sàng chỉ thiết kế cho sự nóng mới.

+1

cho những người sau đây cùng ở nhà, tôi đã quyết định đi với lỗi ngoài và làm theo lời khuyên của Ninncanner của Quinn. vì vậy phương pháp cụ thể này sẽ là một cái gì đó như: '- (BOOL) getNumber: (CGFloat *) outNum lỗi: (NSError **) outErr;' –

+0

@olliej chỉ ra một cách chính xác rằng các khối @try là "zero cost" trong thời gian chạy hiện đại (64-bit và iPhone), nhưng ngoại lệ vẫn còn chi phí khi bạn thực sự ném chúng. Ngoài ra, bạn có thể sử dụng 'double' thay cho' CGFloat' nếu muốn. Đi với bất cứ điều gì là thực hành tốt nhất cho môi trường bạn đang ở và mã bạn tích hợp với. –

Trả lời

16

Bạn nên chắc chắn tránh ngoại lệ cho những thứ như phân tích cú pháp số từ chuỗi. Trong Objective-C, các ngoại lệ biểu diễn lỗi lập trình viên, không phải lỗi đầu vào của người dùng hoặc thậm chí các tệp không khả dụng. (Một phần lý do là việc xử lý ngoại lệ luôn tốn kém và phức tạp hơn việc xử lý lỗi "thông thường". Bất kể thực tế là entering @try blocks is "zero cost" in 64-bit, nó vẫn chậm bất cứ khi nào một ngoại lệ thực sự được nâng lên.) Tất nhiên, bạn được phép sử dụng ngoại lệ như bạn thích, nhưng nó không phải là cách Cocoa, và bạn sẽ thấy mình ở tỷ lệ cược với mã Objective-C khác. Những người sử dụng mã của bạn sẽ vô cùng khó chịu khi bạn ném ngoại lệ trong các trường hợp chỉ dẫn đến lỗi.

Từ Apple's own docs:

"In many environments, use of exceptions is fairly commonplace. For example, you might throw an exception to signal that a routine could not execute normally—such as when a file is missing or data could not be parsed correctly. Exceptions are resource-intensive in Objective-C. You should not use exceptions for general flow-control, or simply to signify errors. Instead you should use the return value of a method or function to indicate that an error has occurred, and provide information about the problem in an error object."

Nhìn vào cách tích hợp các lớp Cocoa xử lý các lỗi như thế này. Ví dụ: NSString có các phương thức như -floatValue trả về 0 nếu không thành công.Một giải pháp tốt hơn cho trường hợp cụ thể của bạn có thể là cách NSScanner thực hiện, chẳng hạn như trong -scanFloat: - chấp nhận con trỏ đến trường nơi kết quả sẽ được lưu trữ và trả lại YES hoặc NO dựa trên việc phân tích cú pháp thành công hay không.

Ngoài quy ước Obejctive-C và thực tiễn tốt nhất, NSError mạnh mẽ và linh hoạt hơn nhiều so với NSException, và cho phép người gọi có thể bỏ qua vấn đề nếu họ muốn. Tôi đề nghị đọc qua số Error Handling Programming Guide For Cocoa. Lưu ý: Nếu bạn chấp nhận thông số NSError**, tôi khuyên bạn cũng nên thiết kế để cho phép khách hàng vượt qua NULL nếu họ không muốn nhận bất kỳ thông tin lỗi nào. Mỗi lớp Cocoa tôi nhận thức được điều này cho các lỗi, bao gồm cả NSString.

Mặc dù mã được chuyển có thể trông hoàn toàn khác với mã Java, nhận ra rằng mã sẽ được sử dụng bởi mã Objective-C, không phải là các máy khách tương tự của Java tương đương. Chắc chắn phù hợp với các thành ngữ của ngôn ngữ. Cổng sẽ không phải là một hình ảnh phản chiếu của mã Java, nhưng kết quả sẽ chính xác hơn (đối với mục tiêu-C).

+0

thx cho phản hồi của bạn Quinn –

+1

tôi đặc biệt thích lời khuyên của 'NSScanner' ... sẽ giúp làm sạch các tên phương thức này một chút và khiến chúng trở nên tự nhiên hơn trong ObjC. –

-1

Trường hợp ngoại lệ có lẽ là cách tiếp cận tốt nhất, vì 64-bit Obj-C ABI (thời gian chạy) sử dụng các ngoại lệ chi phí bằng 0, vì vậy bạn nhận được mã sạch hơn mà không tốn chi phí thực. Tất nhiên trong 32-bit, các ngoại lệ setjmp/longjmp cũ vẫn đang được sử dụng và chúng không tương tác với C++ vì vậy nếu đó là một mục tiêu thì bạn có một vấn đề.

+0

thx cho oliver phản hồi tuyệt vời. và cho hồ sơ, không. tôi sẽ không trộn lẫn codebase này với C++ theo bất kỳ cách nào. –

+0

-1 Xin lỗi, nhưng đây là lời khuyên TERRIBLE cho Mục tiêu-C. Không phải tất cả các ngoại lệ đều là "không có chi phí", chỉ những ngoại lệ không bao giờ thực sự xảy ra là (giống như các khóa không được kiểm soát khi lập trình với sự đồng thời). Khoảnh khắc bạn nêu lên ("ném") một ngoại lệ, bạn phải trả giá. Tuyên bố rằng kết quả trong "mã sạch hơn" là một cá trích đỏ, bởi vì mặc dù mã thư viện chỉ có thể tăng ngoại lệ, mỗi khách hàng đơn lẻ phải đối phó với ngoại lệ bằng cách sử dụng @try và @catch. "Cách ca cao" là sử dụng các lỗi và trả lại mã cho các tình huống như vậy. Nếu bạn muốn cổng là mã Objective-C tốt, KHÔNG SỬ DỤNG EXCEPTIONS. –

+1

@Quinn: "Không có chi phí" ngoại lệ là một thuật ngữ được hiểu rõ ràng, cụ thể là không có chi phí nếu ngoại lệ không được ném.32-bit Obj-C ABI sử dụng setjmp và longjmp để thực hiện các ngoại lệ, có nghĩa là @ try/@ catch có một chi phí lớn cho dù ngoại lệ được ném hay không. – olliej

3

Bạn nói đúng rằng "lỗi ngoài thường là giải pháp tốt hơn cho ObjC". Rất hiếm khi bạn sẽ tìm thấy một API trong Cocoa mà ném một ngoại lệ (trừ khi bạn không hài lòng các điều kiện tiên quyết cho API, nhưng trong trường hợp đó, hành vi là không xác định theo mặc định).

Nếu bạn mong đợi mã này tồn tại bên ngoài bạn và được các nhà phát triển Cocoa khác chấp nhận, tôi khuyên bạn nên sử dụng lỗi ngoài. Tôi làm việc trên mã được xây dựng bởi những người không quen thuộc với Cocoa và người đã sử dụng ngoại lệ tự do, và họ là một nỗi đau hoàng gia để làm việc xung quanh.

7

Trong ca cao, ngoại lệ thực sự chỉ được sử dụng cho "lỗi lập trình"; triết lý là để cho ứng dụng bắt chúng, cung cấp cho người dùng tùy chọn để lưu những gì họ đang làm và thoát. Đối với một điều, không phải tất cả các khuôn khổ hoặc đường dẫn mã có thể là 100% ngoại lệ an toàn, vì vậy đây có thể là hành động an toàn duy nhất. Đối với các lỗi có thể được dự đoán và phục hồi, bạn nên sử dụng NSError, thường thông qua một tham số ngoài.

+1

Các ngoại lệ của Objective-C tương tự như cách mà Lỗi được định nghĩa trong Java: bạn không được mong đợi xử lý chúng, mà đúng hơn là tắt một cách duyên dáng. –

2

Tôi là một fan hâm mộ lớn của phương pháp tiếp cận lỗi mà Objective-C sử dụng. Bạn phải xử lý các ngoại lệ, nhưng bạn có thể chọn bỏ qua các lỗi nếu bạn muốn. Tất cả đều phù hợp với thái độ Objective-C rằng "lập trình viên biết họ đang làm gì." Nó cũng làm cho Objective-C trở thành một ngôn ngữ rất sạch sẽ, bởi vì mã của bạn không bị lộn xộn với các khối try-catch.

Điều đó nói rằng - bạn có thể muốn xem xét: Có bất kỳ trường hợp nào mà ngoại lệ bị bỏ qua không? Có phải ngoại lệ bạn ném thực sự quan trọng? Bạn có thấy mình viết các khối catch đơn giản làm sạch các biến và tiếp tục không? Tôi muốn loại bỏ các lỗi vì tôi thích cú pháp và Objective-C dự trữ ngoại lệ cho các lỗi nghiêm trọng nhất.

+0

giờ, cũng trong nguồn Java, đây là những trường hợp ngoại lệ * được kiểm tra *, do đó, với thiết kế hiện tại, có, chúng hoàn toàn phải được xử lý. về thời điểm chúng thực sự quan trọng, tôi cho rằng đó là một câu hỏi khó khăn hơn. Có thể chúng không thực sự quan trọng và tác giả gốc chỉ tận dụng được tính năng tốt đẹp của ngôn ngữ gốc (Java). Tôi sẽ nói .... tôi có sự tôn trọng cao nhất đối với tác giả gốc. ông chắc chắn biết công cụ của mình (trong Java ít nhất). –

+0

+1 Để chắc chắn, không có sự thiếu tôn trọng nào dành cho tác giả gốc. Khi tôi viết bằng Java, tôi tuân theo các quy ước (cả ngôn ngữ lẫn nhóm của tôi) và thường ném các ngoại lệ đã kiểm tra trong các trường hợp tương tự. Đó là xem xét nhiều hơn về bối cảnh và những gì phù hợp nhất với một bối cảnh nhất định. Nó cũng tốt đẹp để cho khách hàng quyết định khi nó thực sự quan trọng để xử lý một lỗi, thay vì luôn luôn phải bảo vệ chống lại một NumberFormatException, NullPointerException, vv –

2

Trông giống như các ngoại lệ đã kiểm tra này, hãy lập bản đồ rõ ràng hơn để tìm ra lỗi. Ngoại lệ vẫn có thể được sử dụng, nhưng nên được dành riêng cho các trường hợp ngoại lệ.

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