Câu hỏi Có một sự khác biệt giữa một biến "instance" và "property" trong Objective-c không?


Có một sự khác biệt giữa một biến "instance" và "property" trong Objective-c không?

Tôi không chắc lắm về điều này. Tôi nghĩ rằng một "thuộc tính" là một biến cá thể có các phương thức accessor, nhưng tôi có thể nghĩ sai.


76
2018-05-09 16:53


gốc




Các câu trả lời:


Một tài sản là một khái niệm trừu tượng hơn. Một biến mẫu là nghĩa đen chỉ là một khe lưu trữ, giống như một khe trong một cấu trúc. Thông thường các đối tượng khác không bao giờ được phép truy cập trực tiếp chúng. Một thuộc tính, mặt khác, là một thuộc tính của đối tượng của bạn có thể được truy cập (nó có vẻ mơ hồ và nó được cho là). Thông thường một thuộc tính sẽ trả về hoặc thiết lập một biến cá thể, nhưng nó có thể sử dụng dữ liệu từ một số hoặc không có gì cả. Ví dụ:

@interface Person : NSObject {
    NSString *name;
}

    @property(copy) NSString *name;
    @property(copy) NSString *firstName;
    @property(copy) NSString *lastName;
@end

@implementation Person
    @synthesize name;

    - (NSString *)firstName {
        [[name componentsSeparatedByString:@" "] objectAtIndex:0];
    }
    - (NSString *)lastName {
        [[name componentsSeparatedByString:@" "] lastObject];
    }
    - (NSString *)setFirstName:(NSString *)newName {
        NSArray *nameArray = [name componentsSeparatedByString:@" "];
        NSArray *newNameArray [[NSArray arrayWithObjects:newName, nil] arrayByAddingObjectsFromArray:[nameArray subarrayWithRange:NSMakeRange(1, [nameArray size]-1)]];
        self.name = [newNameArray componentsJoinedByString:@" "];
    }
    - (NSString *)setLastName:(NSString *)newName {
        NSArray *nameArray = [name componentsSeparatedByString:@" "];
        NSArray *newNameArray [[nameArray subarrayWithRange:NSMakeRange(0, [nameArray size]-2)] arrayByAddingObjectsFromArray:[NSArray arrayWithObjects:newName, nil]];
        self.name = [newNameArray componentsJoinedByString:@" "];
    }
@end

(Lưu ý: Mã trên là lỗi ở chỗ nó giả định tên đã tồn tại và có ít nhất hai thành phần (ví dụ "Bill Gates" thay vì chỉ "Gates"). Tôi cảm thấy rằng việc sửa các giả định đó sẽ làm cho điểm thực của mã ít rõ ràng hơn, vì vậy tôi chỉ chỉ ra nó ở đây để không ai ngây thơ lặp lại những sai lầm đó.)


81
2018-05-09 17:29



Cách mà tôi đã xem tài sản là một phương tiện cung cấp / hạn chế quyền truy cập vào các biến cá thể cho các đối tượng bên ngoài. Loại giống như khái niệm công / tư ở các ngôn ngữ khác? - prototypical
"Thông thường các đối tượng khác không bao giờ được phép truy cập trực tiếp", bạn có ý gì? Ngoài ra câu trả lời của bạn được cập nhật với mục tiêu-c hiện đại? - Honey
@ Tôi nghĩ anh ấy đang nói đến khái niệm đóng gói và thực hành tốt nhất. Các đối tượng khác không thể trực tiếp truy cập hoặc sửa đổi ivar. Bằng cách kiểm soát truy cập ivar thông qua các thuộc tính, chúng ta có thể chặn các cuộc gọi đó trước khi chúng có khả năng ảnh hưởng đến ngà voi. Xem ở đây để biết thêm: en.wikipedia.org/wiki/Encapsulation_(computer_programming) - user3344977


Thuộc tính là một cách thân thiện để triển khai trình lấy / đặt cho một số giá trị, với các tính năng và cú pháp bổ sung hữu ích. Một thuộc tính có thể được hỗ trợ bởi một biến cá thể, nhưng bạn cũng có thể định nghĩa getter / setter để làm điều gì đó năng động hơn một chút, ví dụ: bạn có thể định nghĩa thuộc tính lowerCase trên một chuỗi tự động tạo kết quả thay vì trả về giá trị của một số biến thành viên.

Đây là một ví dụ:

// === In your .h ===

@interface MyObject {
    NSString *propertyName;

}

// ...

@property (nonatomic, retain) NSString *propertyName;

// === In your .m @implementation ===

@synthesize propertyName /* = otherVarName */;

Các @property dòng xác định một thuộc tính được gọi là propertyName loại NSString *. Điều này có thể nhận / đặt bằng cú pháp sau:

myObject.propertyName = @"Hello World!";
NSLog("Value: %@", myObject.propertyName);

Khi bạn chỉ định hoặc đọc từ myObject.propertyName bạn đang thực sự gọi phương thức setter / getter trên đối tượng.

Các @synthesize dòng lệnh cho trình biên dịch tạo ra các getter / setters này cho bạn, sử dụng biến thành viên có cùng tên của thuộc tính để lưu trữ giá trị (hoặc otherVarName nếu bạn sử dụng cú pháp trong phần bình luận).

Cùng với @synthesize bạn vẫn có thể ghi đè lên một trong các getter / setters bằng cách xác định của riêng bạn. Quy ước đặt tên cho các phương thức này là setPropertyName: cho setter và propertyName (hoặc là getPropertyName, không tiêu chuẩn) cho getter. Người khác sẽ vẫn được tạo cho bạn.

Trong của bạn @property dòng, bạn có thể xác định một số thuộc tính trong parens cho thuộc tính có thể tự động hóa những thứ như an toàn luồng và quản lý bộ nhớ. Theo mặc định, thuộc tính có nghĩa là nguyên tử, trình biên dịch sẽ bao bọc @synthesized có được / thiết lập cuộc gọi với khóa thích hợp để ngăn chặn các vấn đề tương tranh. Bạn có thể chỉ định nonatomic để tắt tính năng này (ví dụ trên iPhone bạn muốn mặc định hầu hết các thuộc tính nonatomic).

Có 3 giá trị thuộc tính kiểm soát quản lý bộ nhớ cho bất kỳ @synthesized người định cư. Đầu tiên là retain sẽ tự động gửi release với các giá trị cũ của tài sản và retain với các giá trị mới. Điều này rất hữu ích.

Thứ hai là copy sẽ tạo một bản sao của bất kỳ giá trị nào được chuyển vào thay vì giữ lại chúng. Thực hành tốt là sử dụng copycho NSString vì người gọi có thể vượt qua trong NSMutableString và thay đổi nó từ bên dưới bạn. copy sẽ tạo một bản sao đầu vào mới mà chỉ bạn mới có quyền truy cập vào.

Thứ ba là assign mà làm một con trỏ thẳng chỉ định mà không cần gọi giữ lại / phát hành trên đối tượng cũ hoặc mới.

Cuối cùng, bạn cũng có thể sử dụng readonly để vô hiệu hóa setter cho thuộc tính.


30
2018-05-09 17:53



Có lợi ích nào khi khai báo biến cá thể và thuộc tính (ví dụ: propertyName) không? Việc khai báo bên trong giao diện là không cần thiết nếu bạn khai báo một thuộc tính cho cùng một biến, đúng không? Điều này thực sự tiết kiệm trên dòng mã, trừ khi có một cái gì đó tôi đang thiếu .. - whyoz


Tôi sử dụng các thuộc tính cho phần giao diện - nơi mà đối tượng giao tiếp với các đối tượng khác và các biến mẫu là những thứ bạn cần bên trong lớp của bạn - không ai nhưng bạn có nghĩa vụ phải xem và thao tác chúng.


6
2018-06-15 13:54





Theo mặc định, một thuộc tính readwrite sẽ được hỗ trợ bởi một biến cá thể, một biến sẽ được tổng hợp tự động bởi trình biên dịch.

Một biến cá thể là một biến tồn tại và giữ giá trị của nó cho tuổi thọ của đối tượng. Bộ nhớ được sử dụng cho các biến mẫu được cấp phát khi đối tượng được tạo lần đầu tiên (thông qua phân bổ) và được giải phóng khi đối tượng được deallocated.

Trừ khi bạn chỉ định khác, biến cá thể tổng hợp có cùng tên với thuộc tính, nhưng với tiền tố gạch dưới. Đối với một thuộc tính được gọi là firstName, ví dụ, biến cá thể tổng hợp sẽ được gọi là _firstName.


3
2018-05-28 11:13





Trước đây mọi người sử dụng các thuộc tính công khai và ivars để sử dụng riêng tư, nhưng kể từ vài năm trước, bạn cũng có thể xác định các thuộc tính trong @implementation để sử dụng chúng một cách riêng tư. Nhưng tôi vẫn sử dụng ngà voi khi có thể, vì có ít chữ cái hơn để gõ, và nó chạy nhanh hơn theo bài viết này. Nó có ý nghĩa vì các thuộc tính có nghĩa là "nặng": chúng có nghĩa vụ phải được truy cập từ các getters / setters được tạo ra hoặc các thuộc tính được viết thủ công.

Tuy nhiên, trong các mã gần đây từ Apple, các mã vạch không được sử dụng nữa. Tôi đoán bởi vì nó giống như objc thay vì C/C++, cộng với việc sử dụng các thuộc tính dễ dàng hơn assign, nullable, v.v.


1
2018-06-07 13:15