Tôi đã học được điều gì đó mới trong khi cố gắng tìm ra lý do tại sao thuộc tính ghi đè của tôi được khai báo trong Danh mục riêng tư không tạo ra trình thiết lập. Nó được vì loại của tôi đã được đặt tên:Minutia về Mục tiêu-C Thể loại và Tiện ích mở rộng
// .m
@interface MyClass (private)
@property (readwrite, copy) NSArray* myProperty;
@end
Thay đổi nó để:
// .m
@interface MyClass()
@property (readwrite, copy) NSArray* myProperty;
@end
và setter của tôi được tổng hợp. Bây giờ tôi biết rằng Lớp mở rộng không chỉ là một tên khác cho một Danh mục ẩn danh. Rời khỏi một danh mục chưa được đặt tên khiến nó biến thành một con thú khác: một cái bây giờ cho phép thực thi phương thức thực hiện biên dịch-thời gian và cho phép bạn thêm các con ngà. Bây giờ tôi đã hiểu được những triết lý chung bên dưới mỗi loại: Các danh mục thường được sử dụng để thêm các phương thức vào bất kỳ lớp nào trong thời gian chạy và Lớp mở rộng thường được sử dụng để thực thi triển khai API riêng tư và thêm ivars. Tôi chấp nhận điều này.
Nhưng có những trò lừa đảo làm tôi bối rối. Đầu tiên, ở cấp độ cao: Tại sao lại phân biệt như thế này? Những khái niệm này có vẻ giống như những ý tưởng tương tự mà không thể quyết định xem chúng có giống nhau hay các khái niệm khác nhau hay không. Nếu chúng giống nhau, tôi sẽ mong đợi những điều tương tự chính xác có thể bằng cách sử dụng Danh mục không có tên như với Danh mục có tên (mà chúng không có). Nếu chúng khác nhau, (chúng là) Tôi sẽ mong đợi một sự khác biệt về cú pháp giữa hai điều này. Có vẻ kỳ quặc khi nói, "Ồ, nhân tiện, để thực hiện một lớp mở rộng, chỉ cần viết một thể loại, nhưng để lại tên. Nó kỳ diệu thay đổi."
Thứ hai, về chủ đề thực thi biên dịch thời gian: Nếu bạn không thể thêm thuộc tính vào một Danh mục được đặt tên, tại sao làm như vậy thuyết phục trình biên dịch mà bạn đã làm điều đó? Để làm rõ, tôi sẽ minh họa bằng ví dụ của tôi. Tôi có thể khai báo thuộc tính chỉ đọc trong tệp tiêu đề:
// .h
@interface MyClass : NSObject
@property (readonly, copy) NSString* myString;
@end
Bây giờ, tôi muốn chuyển sang tệp triển khai và tự mình đọc quyền truy cập tài sản. Nếu tôi làm đúng:
// .m
@interface MyClass()
@property (readwrite, copy) NSString* myString;
@end
Tôi nhận được cảnh báo khi tôi không tổng hợp và khi tôi làm, tôi có thể đặt thuộc tính và mọi thứ đều có màu đào. Nhưng, kỳ phiền, nếu tôi xảy ra được một chút sai lầm về sự khác biệt giữa các loại và lớp mở rộng và tôi cố gắng:
// .m
@interface MyClass (private)
@property (readwrite, copy) NSString* myString;
@end
Trình biên dịch là hoàn toàn bình định vào suy nghĩ rằng tài sản là readwrite. Tôi không nhận được cảnh báo, và thậm chí không có lỗi biên dịch tốt đẹp "Object không thể được thiết lập - hoặc thuộc tính chỉ đọc hoặc không có setter tìm thấy" khi thiết lập myString mà tôi đã có tôi không khai báo tài sản readwrite trong thể loại. Tôi chỉ nhận được ngoại lệ "Không phản hồi với bộ chọn" khi chạy. Nếu thêm các thuộc tính và các thuộc tính không được hỗ trợ bởi (được đặt tên) Các thể loại, có quá nhiều thứ để yêu cầu trình biên dịch chơi theo cùng các quy tắc không? Tôi có thiếu một số triết lý thiết kế lớn?
Tôi tin rằng bạn có nghĩa là 'readwrite' cho khai báo thuộc tính myString riêng tư. Tôi đã chỉnh sửa để phản ánh điều đó; hy vọng đó là chính xác. –
Thật vậy, tôi đã làm. Cảm ơn. –
Câu hỏi Fantasic! –