Objective-C中的strong和weak有什么区别?

324

在指向对象的指针的@property声明中,strongweak之间有什么区别?

此外,nonatomic是什么意思?


20
实际上这是一个很好的问题,有时候我们会忘记强/弱和原子性/非原子性偏好的基本概念。谢谢你提醒我们。 - caknia
10
有趣的是,我在谷歌上进行了简单的搜索,结果把我带到了这里。#循环引用 - Jason Renaldo
11
我倾向于不相信谷歌上的许多答案,但总是参考 S.O 的智能回答。 - JeffK
9个回答

744

强引用和弱引用可以通过气球来理解。

只要有至少一个人拿着系在气球上的绳子,气球就不会飞走。这里拿着绳子的人数是保留计数。当没有人拿着绳子时,气球就会飞走(被释放)。很多人可以拿着同一个气球的绳子。无论是强引用还是弱引用都可以对引用对象进行属性设置和调用方法。

强引用就像拿着气球的绳子一样。只要你拿着系在气球上的绳子,它就不会飞走。

弱引用则像是看着气球。你可以看到它,访问它的属性,调用它的方法,但你没有和气球相连的绳子。如果所有拿着绳子的人都松手了,气球就会飞走,那么你就无法再访问它了。


75
+2(如果我能的话)!说真的,这个解释太有创意了! - Con Antonakos
28
经过一年半的iOS开发,我现在才真正理解了strongweak的实际含义。 - Isuru
20
保留周期就像你给气球系了两根绳子一样,其中一根绳子是你自己的(这样你就拥有了这个气球),另一根绳子则属于气球本身(所以这个气球拥有了你)。由于你只能访问自己的那根绳子,如果气球不想走,你怎么让它走呢?因此最好的方法是你拥有这个气球(强引用),而气球却不拥有你(弱引用)。当你想要放手时,只需要切断绳子即可 :) - snakeninny
6
阅读他的个人资料,他是一位iOS讲师。非常富有创意的解释!!佩服! - Hemang
3
原子性和非原子性可以比作一个公共厕所,有多个门,中间只有一个马桶。一旦有人通过其中一扇门进入马桶,如果他不想经历尴尬的时刻,他最好把所有其他门都锁上。哈哈,谢谢您阅读这个无聊的比喻。 - Chen Li Yong
显示剩余14条评论

659
强引用(在大多数情况下使用)意味着您想“拥有”您使用此属性/变量引用的对象。编译器将确保只要您使用强引用指向它,就不会销毁分配给此属性的任何对象。只有当您将该属性设置为nil时,对象才会被销毁(除非一个或多个其他对象也保持对其的强引用)。与之相反,使用弱引用表示您不想控制对象的生命周期。您弱引用的对象之所以仍然存在,是因为至少有另一个对象具有强引用。一旦不再满足这种情况,对象将被销毁,您的弱属性将自动设置为nil。iOS中最常见使用弱引用的情况是:
  1. 代理属性通常被弱引用引用,以避免保留循环,和
  2. 视图控制器主视图的子视图/控件,因为这些视图已由主视图强引用
atomic vs. nonatomic 是关于编译器为属性合成的getter和setter方法的线程安全性。atomic(默认)告诉编译器使访问器方法线程安全(通过在访问ivar之前添加锁),而nonatomic则相反。 nonatomic的优点是稍微更高的性能。在iOS上,Apple几乎将nonatomic用于其所有属性,因此一般建议您也这样做。

29
@Bourne:这要取决于你对“线程安全”的理解。atomic保证了一个属性可以在多个线程同时读写时被安全地访问,但这并不意味着所有属性都是atomic的对象自动具备线程安全性。 - Ole Begemann
3
非常详细,直到现在我才真正理解。谢谢。 - ahmedalkaff
1
根据苹果文档,atomic和nonatomic应该是与线程安全相关的同义词。https://developer.apple.com/library/ios/documentation/cocoa/conceptual/ProgrammingWithObjectiveC/EncapsulatingData/EncapsulatingData.html - Murtaza Khursheed Hussain
5
注意:属性的原子性与对象的线程安全不是同义词。 - Onnmir
为什么我们不想要时不能删除实例?为什么我们不能在不需要时把气球放空或摧毁它,为什么我们必须关心附加的字符串?我们只需要数据。 - Ashish P

25

strong:将传入的值分配给它,它将保留传入的值并释放实例变量的现有值。

weak:将分配传入的值但不会保留它。

因此,基本区别在于新变量的保留。通常您想要保留它,但有些情况下您不希望这样做,否则会出现保留循环并且无法释放对象的内存。例如,obj1 保留 obj2 并且 obj2 保留 obj1。为解决这种情况,使用弱引用。


13

一份虚假的答案 :-

我认为上面的答案已经解释得很清楚了,所以我只是告诉你何时使用STRONG和何时使用WEAK

使用Weak :- 1. 代理 2. 插座 3. 子视图 4. 控件等。

使用Strong :- 除了 WEAK 未包括在内的所有其他地方。


3
"并且“等等”包括什么呢? :P" - Rajneesh071
3
webView,mapView等 - shubham mishra
4
事实上,我们在Storyboard上拖放的大多数子视图 - shubham mishra

8
强引用 (strong)弱引用 (weak),这些关键字围绕 Objective-C 中的对象所有权展开。 什么是对象所有权? 指针变量意味着它们所指向的对象的所有权。
  • 当一个方法(或函数)有一个局部变量指向一个对象时,该变量被认为拥有指向的对象。
  • 当一个对象具有指向另一个对象的实例变量时,具有指针的对象被认为拥有被指向的对象。
无论何时指针变量指向一个对象,该对象都有一个所有者并将保持存在。这被称为强引用
一个变量可以选择不拥有它所指向的对象。不拥有对象的变量被称为弱引用
详细解释请参见揭秘@property和属性

7

7

strong 是默认值。只要有强引用指向一个对象,它就会保持“存活”状态。

weak 指定的引用不会使引用的对象保持存活状态。当没有强引用指向对象时,弱引用将被设置为 nil。


4
要理解强引用和弱引用,可以考虑以下示例。假设我们有一个名为“displayLocalVariable”的方法。
 -(void)displayLocalVariable
  {
     UIView* myView = [[UIView alloc] init];
     NSLog(@"myView tag is = %ld", myView.tag);
  }

在上述方法中,myView变量的作用域仅限于displayLocalVariable方法,一旦该方法完成,持有UIView对象的myView变量将从内存中被释放。

现在,如果我们希望在整个视图控制器的生命周期中保持myView变量。为此,我们可以创建一个名为usernameView的属性,该属性将对变量myView拥有强引用(请参见下面代码中的@property(nonatomic,strong) UIView* usernameView;self.usernameView = myView;),如下所示:

@interface LoginViewController ()

@property(nonatomic,strong) UIView* usernameView;
@property(nonatomic,weak) UIView* dummyNameView;

- (void)displayLocalVariable;

@end

@implementation LoginViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

}

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

- (void)displayLocalVariable
{
   UIView* myView = [[UIView alloc] init];
   NSLog(@"myView tag is = %ld", myView.tag);
   self.usernameView = myView;
}

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


@end

在上面的代码中,你可以看到myView被分配给了self.usernameView,而self.usernameView具有对myView的强引用(正如我们在接口中使用@property声明的那样)。因此,只要self.usernameView存在,myView就不会从内存中释放。

  • 弱引用

现在考虑将myName分配给一个弱引用dummyNameView,self.dummyNameView = myView;与强引用不同,弱引用仅在存在对myView的强引用时才会保留myView。请查看下面的代码以了解弱引用的含义:

-(void)displayLocalVariable
  {
     UIView* myView = [[UIView alloc] init];
     NSLog(@"myView tag is = %ld", myView.tag);
     self.dummyNameView = myView;
  }

在上面的代码中,self.dummyNameView对myView有弱引用,但是没有对myView进行强引用,因此self.dummyNameView将无法保留myView的值。

现在再考虑下面的代码:

-(void)displayLocalVariable
      {
         UIView* myView = [[UIView alloc] init];
         NSLog(@"myView tag is = %ld", myView.tag);
         self.usernameView = myView;
         self.dummyNameView = myView;
      } 

在上面的代码中,self.usernameView对myView有一个强引用,因此即使方法结束后,self.dummyNameView仍将具有myView的值,因为myView与之关联的是强引用。
现在,每当我们对变量进行强引用时,它的保留计数会增加1,只有当保留计数达到0时,该变量才会被释放。
希望这能帮到你。

2019-07-25 12:33:15.479002+0530 StrongAndWeak[6329:245483] 我的名字是 = ABC 2019-07-25 12:33:15.479226+0530 StrongAndWeak[6329:245483] 我的强引用名字是 = ABC 2019-07-25 12:33:15.479418+0530 StrongAndWeak[6329:245483] 我的弱引用名字是 = ABC,你说弱属性没有myname的值。但我得到了ABC作为两个引用的值...?能否给出更清晰的答案...先谢谢。 - Raviteja Mathangi
@Raviteja_DevObal ARC不能立即承诺执行它(即释放字符串@"ABC"),但它最终肯定会被释放... - Mahadev Mandale
@Raviteja_DevObal 如此处所述,字符串不是一个好的例子。我已经更新了我的答案,使用UIView对象作为示例,希望能有所帮助。 - Mahadev Mandale

1
强引用: 基本上与我们用于从/到另一个类获取或发送数据的属性一起使用。 弱引用: 通常,从接口中获得的所有出口和连接都是弱类型。 原子性: 在我们不想将我们的出口或对象共享到不同的同时线程中时,使用这种类型的属性。换句话说,原子实例使我们的属性一次只能处理一个线程。 希望对您有所帮助。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接