Bất cứ khi nào tôi triển khai một phương thức trong mã của riêng tôi có thể chấp nhận hoặc trả về các đối tượng của nhiều lớp, tôi luôn cố gắng sử dụng lớp cha cụ thể nhất có sẵn. Ví dụ, nếu tôi định triển khai một phương thức có thể trả về một NSArray * hoặc một NSDictionary * tùy thuộc vào đầu vào của nó, tôi sẽ cung cấp cho phương thức đó kiểu trả về của NSObject *, vì đó là lớp siêu phổ biến trực tiếp nhất. Dưới đây là ví dụ:Tại sao sử dụng (id) trong một chữ ký phương thức khi (NSObject *) sẽ chính xác hơn?
@interface MyParser()
- (BOOL)stringExpressesKeyValuePairs:(NSString *)string;
- (BOOL)stringExpressesAListOfEntities:(NSString *)string;
- (NSArray *)parseArrayFromString:(NSString *)string;
- (NSDictionary *)parseDictionaryFromString:(NSString *)string;
@end
@implementation MyParser
- (NSObject *)parseString:(NSString *)string {
if ([self stringExpressesKeyValuePairs:string]) {
return [self parseDictionaryFromString:string];
}
else if ([self stringExpressesAListOfEntities:string]) {
return [self parseArrayFromString:string];
}
}
// etc...
@end
Tôi đã nhận thấy nhiều trường hợp trong Foundation và các API khác mà Apple sử dụng (id) trong các chữ ký phương thức nhất định khi (NSObject *) sẽ chính xác hơn. Ví dụ, đây là một phương pháp NSPropertyListSerialization:
+ (id)propertyListFromData:(NSData *)data
mutabilityOption:(NSPropertyListMutabilityOptions)opt
format:(NSPropertyListFormat *)format
errorDescription:(NSString **)errorString
Các loại lại có thể từ phương pháp này là NSData, NSString, NSArray, NSDictionary, NSDate, và NSNumber. Dường như với tôi rằng một kiểu trả về (NSObject *) sẽ là một lựa chọn tốt hơn (id), vì người gọi sau đó sẽ có thể gọi các phương thức NSObject như giữ lại mà không có kiểu đúc.
Tôi thường cố gắng mô phỏng thành ngữ được thiết lập bởi các khung chính thức, nhưng tôi cũng muốn hiểu điều gì thúc đẩy họ. Tôi chắc chắn rằng Apple có một số lý do hợp lệ để sử dụng (id) trong các trường hợp như thế này, nhưng tôi chỉ không nhìn thấy nó. Tôi đang thiếu gì?
NSProxy không phải là NSObject. NSObject không phải là lớp gốc duy nhất, do đó, nó không phải là một giả định an toàn rằng mọi thứ sẽ là một lớp con của nó. –