Objective-C ARC: mạnh vs giữ và yếu so với gán


367

Có hai thuộc tính quản lý bộ nhớ mới cho các thuộc tính được ARC giới thiệu strongweak.

Ngoài ra copy, rõ ràng là một cái gì đó hoàn toàn khác nhau, có sự khác biệt nào giữa strongvs retainweakvs assignkhông?

Theo hiểu biết của tôi, sự khác biệt duy nhất ở đây là weaksẽ gán nilcho con trỏ, trong khi assignsẽ không có nghĩa là chương trình sẽ bị sập khi tôi gửi tin nhắn đến con trỏ sau khi nó được phát hành. Nhưng nếu tôi sử dụng weak, điều này sẽ không bao giờ xảy ra, vì tin nhắn gửi đến nilsẽ không làm gì cả.

Tôi không biết về bất kỳ sự khác biệt giữa strongretain.

Có bất kỳ lý do tại sao tôi nên sử dụng assignretaintrong các dự án mới, hoặc là loại bị phản đối?


12
Có ba thuộc tính quản lý bộ nhớ mới cho bất động sản được giới thiệu bởi ARC strong, weakunsafe_unretained.
NJones

5
@NJones Có hai thuộc tính tài sản ( weakstrong) và 4 vòng đời biến ( __strong, __weak, __unsafe_unretained, __autoreleasing). Xem ghi chú ARC bên dưới.
Snowcrash

1
@SnowCrash Có một phiên bản Xcode, có thể là bản xem trước của nhà phát triển, trong đó sử dụng assignkhi biên dịch với ARC là một lỗi. Có rất nhiều câu trả lời bị xóa về điều này. Có vẻ như đã được thay đổi trước khi phát hành cuối cùng. unsafe_unretainedlà thuộc tính ưa thích cho nhiều người trong chúng ta sớm chấp nhận. Để chứng minh đó unsafe_unretainedlà thuộc tính hợp lệ, hãy xem phần "Lập trình với mục tiêu-C" của Apple trong phần "Đóng gói dữ liệu" trong tiêu đề "Sử dụng tài liệu tham khảo không an toàn cho một số lớp". Trong đó nói: "Đối với một tài sản, điều này có nghĩa là sử dụng thuộc tính unsafe_unretained:"
NJones

Câu trả lời:


230

Từ Chuyển đổi sang Ghi chú Phát hành ARC (ví dụ trong phần về thuộc tính thuộc tính).

// The following declaration is a synonym for: @property(retain) MyClass *myObject;

@property(strong) MyClass *myObject;

Như vậy stronglà giống như retaintrong một tuyên bố tài sản.

Đối với các dự án ARC tôi sẽ sử dụng strongthay vì retain, tôi sẽ sử dụng assigncho các thuộc tính nguyên thủy C và weakcho các tham chiếu yếu đến các đối tượng Objective-C.


11
Trong thực tế, theo ARC, đó là lỗi biên dịch để sử dụng assigncho một đối tượng. Bạn phải sử dụng một trong hai weakhoặc unsafe_unretained(không an toàn, rõ ràng) nếu bạn không muốn giữ lại tài sản.
cobbal

5
assignbiên dịch tốt cho tôi trong các dự án ARC với mục tiêu triển khai 4.0.
Pascal

8
@Pascal: tham chiếu yếu không được phép trong các mục tiêu triển khai trong đó hệ điều hành không phải là 5.0 hoặc cao hơn. Vì vậy, đối với các dự án cũ hơn, bạn vẫn có thể sử dụng gán, nhưng nếu bạn chuyển sang các phiên bản mới hơn, bạn phải chuyển sang yếu
Mattia

1
Trông giống như Xcode 4 (với ARC) tạo NSManagedObject lớp con sử dụng retainvs strong. Tôi cho rằng điều đó hầu như vô hại, nhưng tôi tưởng tượng nó nên có strongsự nhất quán ... hoặc có lẽ nó không thành vấn đề. stackoverflow.com/questions/7796476/ Mạnh
Joe D'Andrea

3
@JeremyP Vâng, câu trả lời của bạn là tại chỗ. Tôi đã phản ứng với @Mattia. Tôi đã chỉ ra rằng assignvẫn còn hiệu lực trong một số trường hợp.
Steven Oxley

606

Sau khi đọc rất nhiều bài viết Stackoverflow bài viết và ứng dụng demo để kiểm tra các thuộc tính biến, 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
  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à liên kết bài viết chi tiết nơi bạn có thể tìm thấy ở trên đã đề cập tất cả các thuộc tính, chắc chắn sẽ giúp bạn. 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

1.strong (iOS4 = giữ lại)

  • nó nói "giữ cái này trong đống cho đến khi tôi không chỉ vào nó nữa"
  • nói cách 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.
  • Theo 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 mẽ cho UIViewControllers (cha mẹ của mục UI)
  • mạnh đượ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;

2. yếu -

  • nó nói "giữ điều này miễn là người khác chỉ vào nó mạnh mẽ"
  • điều tương tự như chuyển nhượng, 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 tôi thường sử dụng yếu cho IBOutlets (UIViewControll's Childs). Đ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 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.
  • Yếu 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).

3.retain = mạnh

  • nó được giữ lại, giá trị cũ được giải phóng và nó được chỉ định giữ lại chỉ định giá trị mới sẽ được gửi
  • giữ lại trên nhiệm vụ và giá trị cũ đã gửi
  • giữ lại cũng giống như mạnh mẽ.
  • apple nói nếu bạn viết giữ nó sẽ tự động chuyển đổi / hoạt động như mạnh.
  • các phương thức như "alloc" bao gồm "giữ lại" ngầm định

Thí dụ:

@property (nonatomic, retain) NSString *name;

@synthesize name;

4.đăng ký

  • gán là mặc định và chỉ cần thực hiện một phép gán biến
  • gán là một 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
  • Tô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;

5
2. "tham chiếu yếu là tham chiếu không bảo vệ đối tượng được tham chiếu khỏi bộ sưu tập bởi người thu gom rác" - không có mục tiêu nào trong mục tiêu c là trình thu gom rác;
bucherland

1
và hệ thống phân cấp này được quản lý bởi iOS tự động. Đọc về khái niệm MVC. Ý tôi là khi ViewContorller được trình bày, iOS sẽ tải phân cấp chế độ xem trên màn hình (tạo các chế độ xem bị thiếu). Khi các ViewContoder khác được trình bày, hệ thống phân cấp các khung nhìn đầu tiên này sẽ bị hủy. Nhưng nếu bạn có 'mạnh' trong ViewContoder, thì chế độ xem này không thể bị hủy bỏ khi màn hình tắt. Điều này có thể có tác động mạnh đến bộ nhớ thiết bị và nguyên nhân làm chậm ứng dụng. (Tất nhiên thiết bị có rất nhiều bộ nhớ và bạn chắc chắn sẽ ổn trên ứng dụng màn hình 5-10, nhưng trong ứng dụng lớn, bạn sẽ gặp rắc rối)
bucherland

1
Khi chúng ta sử dụng yếu? 1. Đối với các đối tượng UI, 2. đại biểu, 3. các khối (nên sử dụng yếu hơn bản thân để tránh chu kỳ bộ nhớ (như đã đề cập ở trên)
bucherland

1
Có một sai lầm trong câu trả lời tuyệt vời này - mạnh mẽ - "ARC tự động phát hành nó cho bạn khi bạn hoàn thành nó", điều này không đúng. ARC sẽ tự động giải phóng các đối tượng yếu khi không có con trỏ tới chúng. Mạnh - là từ đồng nghĩa để giữ lại, vì vậy đối tượng được giữ lại và chúng tôi có trách nhiệm làm cho đối tượng không
Ashwin G

1
@RDC, defaultcó nghĩa là gì? Nếu tôi sử dụng @property (nonatomic) NSString *stringnó là strong? Hay là assign? Bởi vì cả hai đều là mặc định.
Iulian Onofrei

40

không nguyên tử / nguyên tử

  • nonatomic nhanh hơn nhiều so với nguyên tử
  • luôn luôn sử dụng nonatomic trừ khi bạn có một yêu cầu rất cụ thể đối với nguyên tử, điều này rất hiếm (nguyên tử không đảm bảo an toàn cho luồng - chỉ có các quầy hàng truy cập vào tài sản khi nó được đặt bởi một luồng khác)

mạnh / yếu / giao

  • sử dụng mạnh để giữ lại các đối tượng - mặc dù từ khóa giữ lại là đồng nghĩa, tốt nhất nên sử dụng mạnh mẽ thay thế
  • sử dụng yếu nếu bạn chỉ muốn một con trỏ tới đối tượng mà không giữ lại nó - hữu ích để tránh giữ chu kỳ (ví dụ: đại biểu) - nó sẽ tự động làm mất con trỏ khi đối tượng được giải phóng
  • sử dụng gán cho nguyên thủy - chính xác như yếu trừ khi nó không làm mất đối tượng khi được phát hành (được đặt mặc định)

(Không bắt buộc)

bản sao

  • sử dụng nó để tạo một bản sao nông của đối tượng
  • thực hành tốt để luôn đặt các thuộc tính bất biến thành sao chép - vì các phiên bản có thể thay đổi có thể được chuyển thành các thuộc tính bất biến, sao chép sẽ đảm bảo rằng bạn sẽ luôn luôn xử lý một đối tượng bất biến
  • nếu một đối tượng bất biến được truyền vào, nó sẽ giữ lại nó - nếu một đối tượng có thể thay đổi được truyền vào, nó sẽ sao chép nó

chỉ đọc

  • sử dụng nó để vô hiệu hóa cài đặt của thuộc tính (ngăn không cho mã biên dịch nếu có vi phạm)
  • bạn có thể thay đổi những gì được phân phối bởi getter bằng cách thay đổi biến trực tiếp thông qua biến thể hiện của nó hoặc trong chính phương thức getter

@Sakthimuthiah là đúng, bạn phải sửa câu trả lời của mình.
Zodiac Toderici

@Sakthimuthiah là không chính xác (và bất cứ ai khác nói nó là). Nguyên tử KHÔNG làm cho nó trở nên an toàn, mặc dù nó có thể dễ bị nhầm lẫn do hành vi của nó. Vui lòng đọc: stackoverflow.com/questions/12347236/ Kẻ
Chris J

39

Theo như tôi biết, strongretainlà từ đồng nghĩa, vì vậy họ làm chính xác như vậy.

Sau đó, weakgần giống như assign, nhưng tự động được đặt thành không sau khi đối tượng, nó được trỏ đến, được giải phóng.

Điều đó có nghĩa, bạn chỉ cần thay thế chúng.

Tuy nhiên , có một trường hợp đặc biệt tôi gặp phải, nơi tôi phải sử dụng assign, thay vì weak. Hãy nói rằng chúng ta có hai thuộc tính delegateAssigndelegateWeak. Trong cả hai được lưu trữ đại biểu của chúng tôi, đó là sở hữu chúng tôi bằng cách có tài liệu tham khảo mạnh mẽ duy nhất. Các đại biểu đang giải quyết, vì vậy -deallocphương pháp của chúng tôi được gọi là quá.

// Our delegate is deallocating and there is no other strong ref.
- (void)dealloc {
    [delegateWeak doSomething];
    [delegateAssign doSomething];
}

Đại biểu đã trong quá trình giải quyết, nhưng vẫn chưa được giải quyết đầy đủ. Vấn đề là các weaktài liệu tham khảo cho anh ta đã bị vô hiệu hóa! Thuộc tính delegateWeakchứa nil, nhưng delegateAssignchứa đối tượng hợp lệ (với tất cả các thuộc tính đã được phát hành và bị vô hiệu hóa, nhưng vẫn hợp lệ).

// Our delegate is deallocating and there is no other strong ref.
- (void)dealloc {
    [delegateWeak doSomething]; // Does nothing, already nil.
    [delegateAssign doSomething]; // Successful call.
}

Đây là trường hợp khá đặc biệt, nhưng nó tiết lộ cho chúng ta cách các weakbiến đó hoạt động và khi chúng bị vô hiệu hóa.



20

Tài liệu của Clang về Đếm tham chiếu tự động Objective-C (ARC) giải thích rõ ràng về vòng loại quyền sở hữu và công cụ sửa đổi:

Có bốn vòng loại sở hữu:

  • __ autoreleasing
  • __ mạnh
  • __ * không an toàn_unretained *
  • __ yếu

Một loại là nontrivially sở hữu đủ tiêu chuẩn nếu nó có đủ điều kiện với __ autoreleasing , __ mạnh , hoặc __ yếu .

Sau đó, có sáu công cụ sửa đổi quyền sở hữu đối với tài sản khai báo:

  • gán ngụ ý quyền sở hữu __ * unsafe_unretained *.
  • sao chép ngụ ý __ quyền sở hữu mạnh mẽ , cũng như hành vi thông thường của ngữ nghĩa sao chép trên setter.
  • giữ lại ngụ ý __ quyền sở hữu mạnh mẽ .
  • mạnh mẽ ngụ ý __ quyền sở hữu mạnh mẽ .
  • * unsafe_unretained * ngụ ý quyền sở hữu __ * unsafe_unretained *.
  • yếu ngụ ý __ quyền sở hữu yếu .

Ngoại trừ yếu , các sửa đổi này có sẵn trong các chế độ không ARC.

Về mặt ngữ nghĩa, các vòng loại sở hữu có ý nghĩa khác nhau trong năm thao tác được quản lý : Đọc, Chuyển nhượng, Khởi tạo, Hủy và Di chuyển, trong đó hầu hết chúng ta chỉ quan tâm đến sự khác biệt trong hoạt động Chuyển nhượng.

Chuyển nhượng xảy ra khi đánh giá một toán tử gán. Các ngữ nghĩa khác nhau dựa trên trình độ chuyên môn:

  • Cho __ đối tượng mạnh , điểm đầu tiên mới được giữ lại trước tiên; thứ hai, lvalue được tải với ngữ nghĩa nguyên thủy; thứ ba, điểm mới được lưu trữ vào giá trị với ngữ nghĩa nguyên thủy; và cuối cùng, pointee cũ được phát hành. Điều này không được thực hiện nguyên tử; đồng bộ hóa bên ngoài phải được sử dụng để làm cho điều này an toàn khi đối mặt với tải và lưu trữ đồng thời.
  • Cho __ đối tượng yếu , giá trị được cập nhật để trỏ đến điểm mới, trừ khi điểm mới là đối tượng hiện đang được xử lý, trong trường hợp đó, giá trị được cập nhật thành con trỏ null. Điều này phải thực hiện nguyên tử đối với các bài tập khác cho đối tượng, để đọc từ đối tượng và phát hành cuối cùng của điểm mới.
  • Đối với các đối tượng __ * unsafe_unretained *, điểm mới được lưu trữ vào giá trị sử dụng ngữ nghĩa nguyên thủy.
  • Đối __ autoreleasing đối tượng, các pointee mới được giữ lại, autoreleased, và lưu trữ vào vế trái sử dụng ngữ nghĩa nguyên thủy.

Sự khác biệt khác về Đọc, Khởi đầu, Phá hủy và Di chuyển, vui lòng tham khảo Mục 4.2 Ngữ nghĩa trong tài liệu .


6

Để hiểu tham chiếu Mạnh và Yếu, hãy xem xét ví dụ dưới đây, giả sử chúng ta có phương thức có tên là displayLocalVariable.

 -(void)displayLocalVariable
  {
     NSString myName = @"ABC";
     NSLog(@"My name is = %@", myName);
  }

Trong phạm vi phương thức trên, biến myName được giới hạn ở phương thức displayLocalVariable, một khi phương thức kết thúc biến myName đang giữ chuỗi "ABC" sẽ được giải phóng khỏi bộ nhớ.

Bây giờ nếu chúng ta muốn giữ giá trị biến myName trong suốt vòng đời của bộ điều khiển xem. Để làm điều này, chúng ta có thể tạo thuộc tính có tên là tên người dùng sẽ có tham chiếu mạnh đến biến myName (xem self.username = myName;mã bên dưới), như bên dưới,

@interface LoginViewController ()

@property(nonatomic,strong) NSString* username;
@property(nonatomic,weak) NSString* dummyName;

- (void)displayLocalVariable;

@end

@implementation LoginViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

}

-(void)viewWillAppear:(BOOL)animated
{
     [self displayLocalVariable];
}

- (void)displayLocalVariable
{
   NSString myName = @"ABC";
   NSLog(@"My name is = %@", myName);
   self.username = myName;
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
}


@end

Bây giờ trong đoạn mã trên, bạn có thể thấy myName đã được gán cho self.username và self.username đang có một tham chiếu mạnh (như chúng tôi đã khai báo trong giao diện sử dụng @property) cho myName (gián tiếp là nó có tham chiếu mạnh đến chuỗi "ABC"). Do đó, chuỗi myName sẽ không bị xử lý từ bộ nhớ cho đến khi self.username tồn tại.

  • Tham khảo yếu

Bây giờ hãy xem xét việc gán myName cho dummyName là một tham chiếu yếu, self.dummyName = myName; Không giống như tham chiếu mạnh, Weak sẽ chỉ giữ myName cho đến khi có tham chiếu mạnh đến myName. Xem mã dưới đây để hiểu tài liệu tham khảo yếu,

-(void)displayLocalVariable
  {
     NSString myName = @"ABC";
     NSLog(@"My name is = %@", myName);
     self.dummyName = myName;
  }

Trong đoạn mã trên có tham chiếu yếu đến myName (tức là self.dummyName đang có tham chiếu yếu đến myName) nhưng không có tham chiếu mạnh đến myName, do đó self.dummyName sẽ không thể giữ giá trị myName.

Bây giờ một lần nữa xem xét các mã dưới đây,

-(void)displayLocalVariable
      {
         NSString myName = @"ABC";
         NSLog(@"My name is = %@", myName);
         self.username = myName;
         self.dummyName = myName;
      } 

Trong mã trên, self.username có tham chiếu mạnh đến myName, do đó self.dummyName sẽ có giá trị myName ngay cả sau khi phương thức kết thúc do myName có tham chiếu Mạnh được liên kết với nó.

Bây giờ, bất cứ khi nào chúng ta tạo một tham chiếu mạnh đến một biến, số lượng giữ lại của nó sẽ tăng thêm một và biến đó sẽ không nhận được số lượng giữ lại được giải quyết đạt đến 0.

Hi vọng điêu nay co ich.


2

Mạnh:

  • Tài sản sẽ không hủy nhưng chỉ khi bạn đặt thuộc tính thành không thì đối tượng sẽ bị hủy
  • Theo mặc định, tất cả các biến thể hiện và biến cục bộ là con trỏ mạnh.
  • Bạn chỉ sử dụng mạnh nếu bạn cần giữ lại đối tượng.
  • Chúng tôi thường sử dụng mạnh mẽ cho UIViewControllers (cha mẹ của mục UI)
  • IOS 4 (không phải ARC) Chúng tôi có thể sử dụng Giữ lại KeyWord
  • IOS 5 (ARC) Chúng ta có thể sử dụng từ khóa mạnh

Ví dụ: @property (mạnh, không biến đổi) ViewContoder * viewContoder;

@synthesize viewCont điều khiển;

Yếu

Theo mặc định, tự động nhận và đặt thành không

  • Chúng tôi thường sử dụng yếu cho IBOutlets (Con của UIViewContoder) và đại biểu
  • điều tương tự như chuyển nhượng, không giữ lại hoặc phát hành

Ví dụ: @property (yếu, không gây dị ứng) IBOutlet UIButton * myButton;

@synthesize myButton;


1

Sự khác biệt giữa mạnh và giữ:

  • Trong iOS4, mạnh tương đương với giữ lại
  • Điều đó có nghĩa là bạn sở hữu đối tượng và giữ nó trong đống cho đến khi không chỉ vào nó nữa
  • Nếu bạn viết giữ lại, nó sẽ tự động hoạt động như mạnh mẽ

Sự khác biệt giữa yếu và gán:

  • Một tài liệu tham khảo về điểm yếu của người Viking là một tài liệu tham khảo mà bạn không giữ lại và bạn giữ nó miễn là người khác chỉ vào nó một cách mạnh mẽ
  • Khi đối tượng được xử lý lại, thì con trỏ yếu sẽ tự động được đặt thành không
  • Thuộc tính "gán" 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
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.