2011-02-03 26 views
5

Bất cứ ai có thể giải thích sự khác biệt giữa thiết lập someObject = someOtherObject;self.someObject = someOtherObject; nếu someObject là thuộc tính lớp được tạo với @property (nonatomic, retain) SomeType someObject;Khi nào cần truy cập tài sản với bản thân và khi nào thì không?

Để làm rõ tôi có cái gì đó như:

@interface SomeClass : NSObject { 
    SomeType* someObject; 
} 

@property (nonatomic, retain) SomeType* someObject; 

@end 

tôi đã nhận thấy tôi nhận được TRUY CẬP EXC_BAD đôi khi tôi sử dụng tài sản mà không tự và nó có vẻ khá ngẫu nhiên. Khi tôi sử dụng bản thân chương trình của tôi sẽ hoạt động như mong muốn. Tôi không nhận được bất kỳ lỗi trình biên dịch hoặc cảnh báo khi tôi bỏ qua tự vì vậy tôi đoán nó là bằng cách nào đó cú pháp hợp lệ?

+0

Có thể trùng lặp [khi nào tôi nên sử dụng từ khóa tự.] (Http://stackoverflow.com/questions/4080523/when-should-i-use-the-self-keyword) Điều này được hỏi rất thường xuyên, đã làm bạn tìm kiếm trước khi đặt câu hỏi? – zoul

Trả lời

2

Thuộc tính chỉ là một cách thuận tiện để truy cập dữ liệu. Vì vậy, khi bạn khai báo thuộc tính @property (nonatomic, giữ lại) SomeType * someObject; điều này có nghĩa rằng trong truy cập thì sẽ được tổng hợp 2 phương pháp:

getter:

-(SomeType*) someObject { 
    return someObject; 
} 

setter

-(void) setSomeObject:(SomeType*) obj { 
    [someObject release]; 
    someObject = [obj retain]; 
} 

Vì vậy, sự khác biệt chính giữa tài sản và ivars là thuộc tính tự động tạo ra các setter/getter phương pháp (và bạn có thể ghi đè lên chúng). Nhưng khi bạn đang viết someObject = new_val, bạn chỉ cần sao chép tham chiếu đến vị trí bộ nhớ. Không có công việc bổ sung nào được thực hiện ở đó, ngoại trừ một hướng dẫn lắp ráp.

Có một điều nữa cần đề cập: nguyên tử và nonatomic. Với nguyên tử, bộ tổng hợp/getter sẽ đảm bảo rằng toàn bộ giá trị luôn luôn được trả về từ getter hoặc được thiết lập bởi setter, bất kể hoạt động setter trên bất kỳ thread nào khác. Tức là, nếu luồng A ở giữa getter trong khi luồng B gọi setter, một giá trị thực khả thi - một đối tượng tự động, rất có thể - sẽ được trả lại cho người gọi trong A.

Trong trường hợp không phải là không có bảo đảm như vậy được thực hiện. Do đó, nonatomic nhanh hơn đáng kể so với nguyên tử.

Chỉnh sửa: vì vậy nếu bạn có một số biến, được truy cập từ các luồng khác nhau hoặc/và một số công việc bổ sung phải được thực hiện (ví dụ: giữ lại, nâng cao một số cờ ...), thì lựa chọn của bạn là thuộc tính. Nhưng đôi khi bạn có một biến, đó là truy cập rất thường xuyên và truy cập thông qua tài sản có thể dẫn đến một chi phí lớn, bởi vì bộ vi xử lý phải thực hiện nhiều hoạt động hơn để tổng hợp và gọi phương pháp.

4

self.someObject = someOtherObject sử dụng thuộc tính. Thuộc tính tạo ra setters và getters cho bạn. Trong trường hợp của bạn, bạn đã gán thuộc tính retain cho thuộc tính, có nghĩa là một đối tượng được đặt qua thuộc tính này sẽ tự động nhận được thông báo retain làm tăng số lần giữ lại của nó bằng 1. Ngoài ra, giá trị cũ của biến thành viên được gửi một thông báo release làm giảm số lượng giữ lại của nó.

Các khía cạnh đang được phân bổ lại, khi số lượng giữ chân của chúng đạt đến 0. Bạn nhận được một ngoại lệ EXC_BAD_ACCESS nếu bạn cố gắng truy cập đối tượng được phân phối lại (ví dụ: nếu bạn cố gắng phát hành nó thường xuyên).

Trong trường hợp của bạn:

SomeOtherObject *soo = [[SomeOtherObject alloc] init]; //retain count: 1 
self.someObject = soo; //soo's retain count is now 2 
[soo release]; //soo's retain count is 1 again, as self still uses it. 
[self doSomethingWithSoo]; 

Tuy nhiên, nếu bạn không sử dụng các setter, bạn phải không thả soo.

SomeOtherObject *soo = [[SomeOtherObject alloc] init]; //retain count: 1 
someObject = soo; //soo's retain count is still 1 
[soo release]; //soo's retain count is 0, it will be deallocated 
[self doSomethingWithSoo]; //will fail with an EXC_BAD_ACCESS exception, as soo does not exist anymore. 
0

Sự khác biệt giữa hai là:

1) khi bạn không sử dụng "tự". bạn đang gán kết quả trực tiếp cho biến thành viên.

2) khi bạn đang sử dụng "tự". bạn đang gọi phương thức setter trên thuộc tính đó. Nó giống như [self setMyObject: ...];

vì vậy trong trường hợp self.myobject, nó giữ nguyên, và trong trường hợp khác, (không có tự), nếu bạn không sử dụng phân bổ, thì nó sẽ được coi là đối tượng được tự động phát hành.

Trong hầu hết các trường hợp, bạn sẽ thấy bạn muốn sử dụng "tự", ngoại trừ trong quá trình khởi tạo đối tượng.

Bằng cách này, bạn cũng có thể sử dụng để tăng self.someObject = [someOtherObject retain] giữ quầy

1

Đó là tất cả về quản lý bộ nhớ.

Thuộc tính lớp học của bạn someObject đã tạo các trình truy cập có chú thích @property/@synthsize trong tệp .h/.m của bạn.

Khi bạn truy cập thuộc tính của mình với someObject, bạn sẽ truy cập trực tiếp vào thuộc tính. Khi bạn đang truy cập self.someObject, bạn đang gọi cho người truy cập của mình [self someObject] whitch sẽ quản lý bộ nhớ cho bạn.

Vì vậy, khi bạn cần chỉ định thuộc tính lớp, hãy làm sạch self.someObject = someOtherObject; vì bạn sử dụng công cụ đặt và không phải lo lắng về việc giải phóng và giữ lại. Khi setter của bạn được tạo ra với @property (nonatomic, retain) do đó, nó sẽ chăm sóc về việc giữ lại cho bạn.

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