@property giữ lại, gán, sao chép, không biến đổi trong Objective-C


214

Là một người mới biết về Objective-C, ai đó có thể cho tôi cái nhìn tổng quan về việc giữ lại, gán, sao chép và bất kỳ ai khác mà tôi đang thiếu, tuân theo chỉ thị @property không? Họ đang làm gì và tại sao tôi lại muốn sử dụng cái này hơn cái khác?


1
Tên của Apple cho đây là "thuộc tính" hoặc "thuộc tính tài sản"
nevan king

Câu trả lời:


273

Bài viết được liên kết bởi MrMage không còn hoạt động. Vì vậy, đây là những gì tôi đã học được trong quá trình mã hóa (rất) thời gian ngắn của mình trong Objective-C:

nonatomic so với nguyên tử - "nguyên tử" là mặc định. Luôn luôn sử dụng "nonatomic". Tôi không biết tại sao, nhưng cuốn sách tôi đọc nói "hiếm khi có lý do" để sử dụng "nguyên tử". (BTW: Cuốn sách tôi đọc là cuốn sách "Lập trình iOS" của BNR.)

readwrite so với readonly - "readwrite" là mặc định. Khi bạn @synthesize, cả getter và setter sẽ được tạo cho bạn. Nếu bạn sử dụng "readonly", sẽ không có setter nào được tạo. Sử dụng nó cho một giá trị mà bạn không muốn thay đổi sau khi khởi tạo đối tượng.

giữ lại so với bản sao so với gán

  • "gán" là mặc định. Trong setter được tạo bởi @synthesize, giá trị sẽ chỉ được gán cho thuộc tính. Hiểu biết của tôi là "gán" nên được sử dụng cho các thuộc tính không phải con trỏ.
  • "Giữ lại" là cần thiết khi thuộc tính là một con trỏ đến một đối tượng. Trình thiết lập được tạo bởi @synthesize sẽ giữ lại (còn gọi là số đếm giữ lại) đối tượng. Bạn sẽ cần phải giải phóng đối tượng khi bạn kết thúc với nó.
  • "Sao chép" là cần thiết khi đối tượng có thể thay đổi. Sử dụng điều này nếu bạn cần giá trị của đối tượng như hiện tại và bạn không muốn giá trị đó phản ánh bất kỳ thay đổi nào được thực hiện bởi các chủ sở hữu khác của đối tượng. Bạn sẽ cần phải giải phóng đối tượng khi bạn kết thúc với nó bởi vì bạn đang giữ lại bản sao.

@Blamdarot - tôi có cần phát hành nó với ARC không
Dejell

10
@Odelya - Không. Nếu bạn phát hành trong khi sử dụng ARC, tôi tin rằng bạn sẽ gặp lỗi trình biên dịch.
Blamdarot

52
"Luôn luôn sử dụng nonatomic" là lời khuyên tồi. Bạn nên biết những gì bạn đang từ bỏ khi bạn sử dụng nonatomic.
Jesse Rusak

7
Đã đồng ý. Đặc biệt, rất nhiều người dường như không biết rằng các giá trị phi nguyên tử không được giữ lại tự động bởi người nhận. nonatomic thường thích hợp, nhưng hiếm khi lập trình sùng bái hàng hóa.
Catfish_Man

9
Tư vấn để mặc định atomiccũng tệ như tư vấn nonatomic. Không có lựa chọn nào là "chính xác", vì vậy các nhà thiết kế ngôn ngữ đã chọn cách an toàn hơn cho hai giải pháp. Trong thực tế nonatomicnói chung là sự lựa chọn tốt hơn vì nó bỏ qua các khóa chủ đề cực kỳ đắt tiền. Lý do duy nhất để sử dụng atomiclà nếu tài sản của bạn có thể được đặt từ nhiều luồng (trong trường hợp bỏ qua nó có thể dẫn đến phát hành quá mức hoặc rò rỉ).
Adam Kaplan

295

Trước khi bạn biết về các thuộc tính của @property, bạn nên biết việc sử dụng @property là gì.

  • @property cung cấp một cách để xác định thông tin mà một lớp dự định đóng gói. Nếu bạn khai báo một đối tượng / biến bằng @property , thì đối tượng / biến đó sẽ có thể truy cập được vào các lớp khác đang nhập lớp của nó.

  • Nếu bạn khai báo một đối tượng bằng cách sử dụng @property trong tệp tiêu đề, thì bạn phải tổng hợp nó bằng cách sử dụng @synthesize trong tệp thực hiện. Điều này làm cho đối tượng KVC tuân thủ . Theo mặc định, trình biên dịch sẽ tổng hợp các phương thức truy cập cho đối tượng này.

  • phương thức accessor là: setter và getter.

Ví dụ: .h

@interface XYZClass : NSObject
@property (nonatomic, retain) NSString *name;
@end

.m

@implementation XYZClass
@synthesize name;
@end

Bây giờ trình biên dịch sẽ tổng hợp các phương thức accessor cho tên .

XYZClass *obj=[[XYZClass alloc]init];
NSString *name1=[obj name]; // get 'name'
[obj setName:@"liza"]; // first letter of 'name' becomes capital in setter method
  • Danh sách các thuộc tính của @property

    nguyên tử, không biến đổi, giữ lại, sao chép, chỉ đọc, đọc, ghi, mạnh, getter = phương thức, setter = phương thức, unsafe_unretained

  • nguyên tử là hành vi mặc định. Nếu một đối tượng được khai báo là nguyên tử thì nó trở nên an toàn cho luồng. Phương tiện an toàn luồng, tại một thời điểm chỉ một luồng của một thể hiện cụ thể của lớp đó có thể có quyền kiểm soát đối tượng đó.

Nếu luồng đang thực hiện phương thức getter thì luồng khác không thể thực hiện phương thức setter trên đối tượng đó. Nó chậm.

@property NSString *name; //by default atomic`
@property (atomic)NSString *name; // explicitly declared atomic`
  • nonatomic không phải là chủ đề an toàn. Bạn có thể sử dụng thuộc tính nonatomic để chỉ định rằng các bộ truy cập được tổng hợp chỉ đơn giản đặt hoặc trả về một giá trị trực tiếp, không đảm bảo về những gì xảy ra nếu cùng một giá trị được truy cập từ các luồng khác nhau.

Vì lý do này, việc truy cập vào một tài sản không phải là nguyên tử nhanh hơn so với tài sản nguyên tử.

@property (nonatomic)NSString *name;   
  • giữ lại được yêu cầu khi thuộc tính là một con trỏ đến một đối tượng.

Phương thức setter sẽ tăng số lượng giữ lại của đối tượng, do đó nó sẽ chiếm bộ nhớ trong nhóm tự động chạy.

@property (retain)NSString *name;
  • sao chép Nếu bạn sử dụng bản sao, bạn không thể sử dụng giữ lại. Sử dụng bản sao của lớp sẽ chứa bản sao của chính nó.

Ngay cả khi một chuỗi có thể thay đổi được thiết lập và sau đó thay đổi, thì cá thể vẫn nắm bắt bất kỳ giá trị nào nó có tại thời điểm nó được đặt. Không có phương thức setter và getter sẽ được tổng hợp.

@property (copy) NSString *name;

hiện nay,

NSMutableString *nameString = [NSMutableString stringWithString:@"Liza"];    
xyzObj.name = nameString;    
[nameString appendString:@"Pizza"]; 

Tên sẽ không bị ảnh hưởng.

  • chỉ đọc Nếu bạn không muốn cho phép thay đổi thuộc tính thông qua phương thức setter, bạn có thể khai báo thuộc tính chỉ đọc.

Trình biên dịch sẽ tạo ra một getter, nhưng không phải là setter.

@property (readonly) NSString *name;
  • đọc là hành vi mặc định. Bạn không cần chỉ định rõ ràng thuộc tính readwrite.

Nó trái ngược với chỉ đọc.

@property (readwrite) NSString *name;
  • gán sẽ tạo ra một setter gán trực tiếp giá trị cho biến thể hiện, thay vì sao chép hoặc giữ lại nó. Điều này là tốt nhất cho các loại nguyên thủy như NSInteger và CGFloat hoặc các đối tượng bạn không trực tiếp sở hữu, chẳng hạn như các đại biểu.

Hãy ghi nhớ giữ lại và gán về cơ bản có thể hoán đổi cho nhau khi bật bộ sưu tập rác.

@property (assign) NSInteger year;
  • mạnh mẽ là một sự thay thế cho giữ lại.

Nó đi kèm với ARC.

@property (nonatomic, strong) AVPlayer *player; 
  • getter = method Nếu bạn muốn sử dụng một tên khác cho phương thức getter, có thể chỉ định một tên tùy chỉnh bằng cách thêm thuộc tính vào thuộc tính.

Trong trường hợp thuộc tính Boolean (thuộc tính có giá trị CÓ hoặc KHÔNG), theo thông lệ, phương thức getter sẽ bắt đầu bằng từ Từ là is

@property (getter=isFinished) BOOL finished;
  • setter = method Nếu bạn muốn sử dụng một tên khác cho phương thức setter, có thể chỉ định một tên tùy chỉnh bằng cách thêm thuộc tính vào thuộc tính.

Phương pháp nên kết thúc bằng dấu hai chấm.

@property(setter = boolBool:) BOOL finished;
  • unsafe_unretained Có một vài lớp trong Ca cao và Ca cao cảm ứng chưa hỗ trợ các tham chiếu yếu, điều đó có nghĩa là bạn không thể khai báo một thuộc tính yếu hoặc biến cục bộ yếu để theo dõi chúng. Các lớp này bao gồm NSTextView, NSFont và NSColorSpace, v.v. Nếu bạn cần sử dụng một tham chiếu yếu đến một trong các lớp này, bạn phải sử dụng một tham chiếu không an toàn.

Một tham chiếu không an toàn tương tự như một tham chiếu yếu ở chỗ nó không giữ cho đối tượng liên quan của nó tồn tại, nhưng nó sẽ không được đặt thành không nếu đối tượng đích bị hủy.

@property (unsafe_unretained) NSObject *unsafeProperty;

Nếu bạn cần chỉ định nhiều thuộc tính, chỉ cần đưa chúng vào danh sách được phân tách bằng dấu phẩy, như sau:

@property (readonly, getter=isFinished) BOOL finished;

Ngoài ra, yếu có nghĩa là không có số tham chiếu cho đối tượng được tham chiếu đến đối tượng, mà nó được tham chiếu ở tất cả hoặc hoàn toàn không được tham chiếu. Kiểu như "vâng, một cái gì đó đã tham chiếu tôi" so với "9 tài liệu tham khảo cho tôi tồn tại" (đó là những gì mạnh mẽ là như thế).
Alex Zavatone

6
Bỏ qua dòng trong câu trả lời liên quan đến bộ sưu tập rác, vì bộ sưu tập rác không được dùng trong Mac OS X và không tồn tại trong iOS theo tài liệu của Apple .
Basil Bourque

4
"Lưu ý: Tính nguyên tử của tài sản không đồng nghĩa với an toàn luồng của đối tượng." - từ developer.apple.com/l
Library / mac / documentation / Coloa / Contualual / Giả

1
"Nếu bạn khai báo một đối tượng sử dụng @propertytrong tệp tiêu đề, thì bạn phải tổng hợp nó bằng cách sử dụng @synthesizetrong tệp thực hiện." Không phải lúc nào. Ví dụ: "Theo mặc định, một thuộc readwritetính sẽ được hỗ trợ bởi một biến đối tượng, một lần nữa sẽ được tổng hợp tự động bởi trình biên dịch." Từ doc .
Franklin Yu

4
@liza Đây là một câu trả lời tuyệt vời. Tại sao đây không phải là câu trả lời được chấp nhận. Nó truyền đạt một lời giải thích có hiểu biết hơn nhiều so với câu trả lời hiện đang được chấp nhận. Đôi khi tôi không hiểu StackOverflow?
Charles Robertson

149

Sau khi đọc nhiều bài viết, tôi quyết định đặt tất cả các thông tin thuộc tính lại với nhau:

  1. nguyên tử // mặc định
  2. nonatomic
  3. mạnh = giữ lại // mặc định
  4. yếu = không an toàn_unretained
  5. giữ lại
  6. gán // mặc định
  7. không an toàn_unretained
  8. bản sao
  9. chỉ đọc
  10. đọc / ghi mặc định

Dưới đây là một liên kết đến bài viết chi tiết nơi bạn có thể tìm thấy các thuộc tính này.

Rất cám ơn tất cả những người đã đưa ra câu trả lời tốt nhất ở đây !!

Thuộc tính hoặc biến đổi thuộc tính trong iOS

Dưới đây là Mô tả mẫu từ Điều

  1. nguyên tử -Atomic có nghĩa là chỉ có một luồng truy cập vào biến (kiểu tĩnh). -Atomic là chủ đề an toàn. -Nhưng nó hoạt động chậm -atomic là hành vi mặc định -Những người truy cập ngẫu nhiên trong môi trường không được thu gom rác (tức là khi sử dụng giữ lại / phát hành / autorelease) sẽ sử dụng khóa để đảm bảo rằng một luồng khác không can thiệp vào cài đặt / nhận chính xác của giá trị. -it không thực sự là một từ khóa.

Thí dụ :

@property (retain) NSString *name;

@synthesize name;
  1. nonatomic -Nonatomic có nghĩa là nhiều luồng truy cập biến (kiểu động). -Nonatomic là chủ đề không an toàn. -Nhưng nó có hiệu suất nhanh -Nonatomic KHÔNG phải là hành vi mặc định, chúng ta cần thêm từ khóa không biến đổi trong thuộc tính. -it có thể dẫn đến hành vi không mong muốn, khi hai quá trình (luồng) khác nhau truy cập cùng một biến cùng một lúc.

Thí dụ:

@property (nonatomic, retain) NSString *name;

@synthesize name;

Giải thích:

Giả sử có một thuộc tính chuỗi nguyên tử được gọi là "name" và nếu bạn gọi [self setName: @ "A"] từ luồng A, hãy gọi [self setName: @ "B"] từ luồng B và gọi [self name] từ luồng C, sau đó tất cả các hoạt động trên các luồng khác nhau sẽ được thực hiện ser seri có nghĩa là nếu một luồng đang thực thi setter hoặc getter, thì các luồng khác sẽ chờ. Điều này làm cho tài sản "tên" đọc / ghi an toàn nhưng nếu một luồng D khác gọi [phát hành tên] đồng thời thì thao tác này có thể tạo ra sự cố do không có lệnh gọi setter / getter nào liên quan ở đây. Điều đó có nghĩa là một đối tượng được đọc / ghi an toàn (ATOMIC) nhưng không phải là luồng an toàn vì các luồng khác có thể đồng thời gửi bất kỳ loại tin nhắn nào đến đối tượng. Nhà phát triển nên đảm bảo an toàn luồng cho các đối tượng như vậy.

Nếu "tên" thuộc tính là không biến đổi, thì tất cả các luồng trong ví dụ trên - A, B, C và D sẽ thực thi đồng thời tạo ra bất kỳ kết quả không thể đoán trước nào. Trong trường hợp nguyên tử, một trong hai A, B hoặc C sẽ thực thi trước nhưng D vẫn có thể thực thi song song.

  1. mạnh mẽ (iOS4 = giữ lại) -it nói "hãy giữ điều này trong đống cho đến khi tôi không chỉ ra nó nữa" - trong các từ khác "Tôi là chủ sở hữu, bạn không thể giải quyết vấn đề này trước khi nhắm tốt với điều đó giống như giữ lại" - Bạn chỉ sử dụng mạnh nếu bạn cần giữ lại đối tượng. -By mặc định tất cả các biến thể hiện và biến cục bộ là con trỏ mạnh. -Chúng tôi thường sử dụng mạnh cho UIViewControllers (cha mẹ của mục UI) -strong được sử dụng với ARC và về cơ bản nó giúp bạn, bằng cách không phải lo lắng về số lượng giữ lại của một đối tượng. ARC tự động phát hành nó cho bạn khi bạn hoàn thành nó. Sử dụng từ khóa mạnh có nghĩa là bạn sở hữu đối tượng.

Thí dụ:

@property (strong, nonatomic) ViewController *viewController;

@synthesize viewController;
  1. yếu (iOS4 = unsafe_unretained) -it nói "hãy giữ điều này miễn là người khác chỉ vào nó một cách mạnh mẽ" - điều tương tự như gán, không giữ lại hoặc phát hành - Tham chiếu "yếu" là tham chiếu mà bạn không giữ lại. -Chúng ta thường sử dụng yếu cho IBOutlets (Con của UIViewContoder). Điều này hoạt động vì đối tượng con chỉ cần tồn tại miễn là đối tượng cha mẹ làm. -Một tham chiếu yếu là một tham chiếu không bảo vệ đối tượng được tham chiếu khỏi bộ sưu tập bởi trình thu gom rác. -Seak về cơ bản là gán, một tài sản không được giữ lại. Ngoại trừ khi đối tượng được giải phóng, con trỏ yếu sẽ tự động được đặt thành không

Thí dụ :

@property (weak, nonatomic) IBOutlet UIButton *myButton;

@synthesize myButton;

Giải thích mạnh mẽ và yếu, nhờ có BJ Homer :

Hãy tưởng tượng đối tượng của chúng ta là một con chó, và con chó đó muốn chạy trốn (bị xử lý). Con trỏ mạnh mẽ giống như một dây xích trên con chó. Miễn là bạn có dây xích gắn vào con chó, con chó sẽ không chạy trốn. Nếu năm người gắn dây xích của họ vào một con chó, (năm con trỏ mạnh vào một đối tượng), thì con chó sẽ không chạy đi cho đến khi tất cả năm dây xích được tách ra. Con trỏ yếu, mặt khác, giống như những đứa trẻ chỉ vào con chó và nói "Nhìn kìa! Một con chó!" Chừng nào con chó vẫn còn trên dây xích, những đứa trẻ vẫn có thể nhìn thấy con chó, và chúng vẫn sẽ chỉ vào nó. Tuy nhiên, ngay sau khi tất cả các dây xích được tháo ra, con chó chạy đi cho dù có bao nhiêu đứa trẻ đang chỉ vào nó. Ngay khi con trỏ mạnh cuối cùng (dây xích) không còn trỏ đến một đối tượng, đối tượng sẽ bị giải phóng và tất cả các con trỏ yếu sẽ bị loại bỏ. Khi chúng ta sử dụng yếu? Lần duy nhất bạn muốn sử dụng yếu, là nếu bạn muốn tránh chu kỳ giữ lại (ví dụ: cha mẹ giữ lại đứa trẻ và đứa trẻ giữ lại cha mẹ để không bao giờ được thả ra).

  1. giữ lại = mạnh -it được giữ lại, giá trị cũ được giải phóng và nó được chỉ định -retain chỉ định giá trị mới sẽ được gửi - hãy giữ lại khi gán và giá trị cũ được gửi -release -retain giống như mạnh. -apple nói rằng nếu bạn viết giữ lại, nó sẽ tự động chuyển đổi / hoạt động như chỉ mạnh. -methods như "alloc" bao gồm một "giữ lại" ngầm

Thí dụ:

@property (nonatomic, retain) NSString *name;

@synthesize name;
  1. gán -assign là mặc định và chỉ đơn giản thực hiện một phép gán biến -assign là thuộc tính thuộc tính cho trình biên dịch biết cách tổng hợp thực hiện setter của thuộc tính -I sẽ sử dụng gán cho các thuộc tính nguyên thủy C và yếu cho các tham chiếu yếu đến các đối tượng Objective-C.

Thí dụ:

@property (nonatomic, assign) NSString *address;

@synthesize address;
  1. không an toàn_unretained

    -unsafe_unretained là một vòng loại quyền sở hữu cho ARC biết cách chèn các cuộc gọi giữ lại / giải phóng -unafe_unretained là phiên bản ARC của phép gán.

Thí dụ:

@property (nonatomic, unsafe_unretained) NSString *nickName;

@synthesize nickName;
  1. sao chép -copy được yêu cầu khi đối tượng có thể thay đổi. -copy chỉ định giá trị mới sẽ được gửi -copy khi gán và giá trị cũ được gửi -release. -copy giống như giữ lại trả về một đối tượng mà bạn phải giải phóng rõ ràng (ví dụ: trong dealloc) trong các môi trường không được thu gom rác. -Nếu bạn sử dụng bản sao thì bạn vẫn cần phát hành bản đó trong dealloc. -Sử dụng điều này nếu bạn cần giá trị của đối tượng như hiện tại và bạn không muốn giá trị đó phản ánh bất kỳ thay đổi nào được thực hiện bởi các chủ sở hữu khác của đối tượng. Bạn sẽ cần phải giải phóng đối tượng khi bạn kết thúc với nó bởi vì bạn đang giữ lại bản sao.

Thí dụ:

@property (nonatomic, copy) NSArray *myArray;

@synthesize myArray;

2
Tôi nghĩ sau khi cung, giữ lại không được sử dụng nữa.
Mert

1
danh sách đầy đủ bỏ lỡ 2 mục tùy chọn: setter và getter, đây cũng là các tùy chọn duy nhất cần đối số.
Scott Chu

mạnh hoặc giữ lại là mặc định cho chỉ loại đối tượng. Nó không thể được sử dụng cho các loại nguyên thủy.
Saleh men Shohag

9

Thuộc tính nguyên tử có thể được truy cập bởi chỉ một chủ đề tại một thời điểm. Đây là chủ đề an toàn . Mặc định là nguyên tử. Xin lưu ý rằng không có từ khóa nguyên tử

Nonatomic có nghĩa là nhiều luồng có thể truy cập vào mục. Đây là luồng không an toàn

Vì vậy, người ta phải rất cẩn thận trong khi sử dụng nguyên tử. Vì nó ảnh hưởng đến hiệu suất mã của bạn


3
"Lưu ý: Tính nguyên tử của tài sản không đồng nghĩa với an toàn luồng của đối tượng." từ developer.apple.com/library/mac/documentation/Cocoa/Conceptual/...
jk7

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.