Objective-C ARC:强vs保留,弱vs分配


367

ARC strong和引入了两个新的内存管理属性weak

除了copy,这显然是完全不同的,vs vs 之间是否有任何区别?strongretainweakassign

根据我的理解,这里唯一的区别是weak将分配nil给指针,而不会分配给指针,assign这意味着一旦释放指针后,我将消息发送给指针,程序就会崩溃。但是,如果我使用weak,这将永远不会发生,因为发送至的消息nil将无济于事。

我不知道strong和之间的任何区别retain

是否有任何理由为什么我应该使用assign,并retain在新的项目,或者是那种被弃用?


12
有由ARC推出性能三个新的内存管理的属性strongweakunsafe_unretained
NJones

5
@NJones有2点属性的属性(weakstrong)和4个可变寿命限定符(__strong__weak__unsafe_unretained__autoreleasing)。请参阅下面的ARC说明。
Snowcrash

1
@SnowCrash有一个Xcode版本,可能是开发人员预览版,在使用assignARC编译时使用Xcode 是一个错误。有许多关于此的已删除答案。似乎在最终版本之前已更改。unsafe_unretained是我们许多早期采用者的首选属性。有关unsafe_unretained有效属性的证明,请参见“对某些类使用不安全的未保留引用”子标题下的“封装数据”部分下的Apple“使用Objective-C编程”。它说:“对于一个属性,这意味着使用unsafe_unretained属性:”
NJones

Answers:


230

过渡到ARC发行说明(有关属性属性的部分中的示例)。

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

@property(strong) MyClass *myObject;

因此strongretain属性声明中的相同。

对于ARC项目我会用strong,而不是retain,我会用assign对C基本属性,并weak为向Objective-C对象的弱引用。


11
实际上,在ARC下,assign用于对象是编译错误。如果您不想保留该属性,则必须使用weakunsafe_unretained(显然是不安全的)。
cobbal 2012年

5
assign在具有部署目标4.0的ARC项目中,对我来说编译就很好。
Pascal 2012年

8
@Pascal:os不是5.0或更高版本的部署目标中不允许使用弱引用。因此,对于年龄较大的项目,你仍然可以使用分配,但如果你移动到更新的版本,你必须切换到弱
马蒂亚

1
看起来Xcode 4(带有ARC)使用vs. 生成NSManagedObject子类。我想这基本上是无害的,但是我想那应该是为了保持一致性……也许没关系。stackoverflow.com/questions/7796476/…–retainstrongstrong
乔·安德里亚

3
@JeremyP是的,您的答案是正确的。我对@Mattia有反应。我指出这assign在某些情况下仍然有效。
史蒂芬·奥克斯利

606

在阅读了许多Stackoverflow帖子和演示应用程序以检查可变属性属性的文章之后,我决定将所有属性信息放在一起:

  1. 原子//默认
  2. 非原子的
  3. strong =保留//默认
  4. 保留
  5. 分配//默认
  6. unsafe_unretained
  7. 复制
  8. 只读
  9. readwrite //默认

以下是详细的文章链接,您可以在其中找到上述所有属性,这些属性肯定会对您有所帮助。非常感谢在这里给出最佳答案的所有人!!

iOS中的可变属性属性或修饰符

1.strong(iOS4 =保留)

  • 它说:“将其保留在堆中,直到我不再指向它为止”
  • 换句话说:“我是所有者,您不能在保留目标之前将其分配给目标对象”
  • 仅在需要保留对象时才使用Strong。
  • 默认情况下,所有实例变量和局部变量都是强指针。
  • 我们通常对UIViewControllers使用强(UI项的父项)
  • strong与ARC一起使用,它基本上可以帮助您,而不必担心对象的保留计数。完成后,ARC会自动为您释放它。使用关键字Strong意味着您拥有该对象。

例:

@property (strong, nonatomic) ViewController *viewController;

@synthesize viewController;

2.弱 -

  • 它说:“只要有人坚决指出,就保持下去”
  • 与分配相同,没有保留或释放
  • “弱”引用是您不保留的引用。
  • 我们通常对IBOutlets(UIViewController的Childs)使用弱函数,这是有效的,因为子对象只需要与父对象一样存在即可。
  • 弱引用是一种引用,它不能保护所引用的对象免受垃圾收集器的收集。
  • 弱本质上是赋值的,是未保留的属性。除了对象被释放时,弱指针会自动设置为nil

范例:

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

@synthesize myButton;

强弱解释,多亏了BJ Homer

想象我们的对象是一只狗,那只狗想逃跑(被释放)。

强壮的指针就像拴在狗身上。只要您将皮带拴在狗上,狗就不会跑开。如果有五个人将皮带拴在一只狗上(五个强力指针指向一个物体),则只有将所有五个皮带分开后,狗才会逃跑。

另一方面,较弱的指针就像小孩指着狗说:“看!狗!” 只要这只狗仍系在皮带上,小孩子仍然可以看到它,他们仍会指向它。但是,一旦所有的皮带都松了,无论有多少小孩指向它,狗都会跑开。

一旦最后一个强指针(皮带)不再指向对象,该对象将被释放,并且所有弱指针将被清零。

什么时候用弱?

您唯一想使用弱函数的情况是,如果您想避免保留周期(例如,父母保留了孩子,孩子保留了父母,因此都不会被释放)。

3.保留=强

  • 它被保留,旧值被释放并被分配了保留,指定应发送新值
  • 保留赋值并发送旧值-release
  • 保留与坚强相同。
  • 苹果说,如果您写保留,它将自动转换/仅像强一样工作。
  • 像“分配”这样的方法包括一个隐式的“保留”

例:

@property (nonatomic, retain) NSString *name;

@synthesize name;

4.分配

  • 指定是默认值,仅执行变量分配
  • Assign是一个属性属性,它告诉编译器如何综合该属性的setter实现
  • 我将对C基本属性使用assign,对Objective-C对象的弱引用使用weak。

例:

@property (nonatomic, assign) NSString *address;

@synthesize address;

5
2.“弱引用是不能保护被引用对象不被垃圾收集器收集的引用” –在目标c中没有垃圾收集器这样的东西;
bucherland 2015年

1
并且此层次结构由iOS自动管理。了解有关MVC概念的信息。我的意思是,当iOS呈现ViewContorller时,它将在屏幕上加载其视图层次结构(创建丢失的视图)。当提供其他ViewController时,该第一个视图层次结构将被释放。但是,如果您在ViewController中具有“ strong”功能,则在屏幕外时,无法重新分配此视图。这可能会对设备内存造成严重影响,并导致应用程序运行缓慢。(设备当然有很多内存,在5-10屏幕的应用程序上肯定可以,但是在大型应用程序中会遇到麻烦)
bucherland 2015年

1
什么时候用弱?1.对于UI对象,2.委托,3.块(应使用weakSelf代替self以避免内存循环(如上所述)
bucherland 2015年

1
这个好答案有一个错误-强烈-“ ARC完成后会自动为您释放它”,这是不对的。当没有指针指向弱对象时,ARC将自动释放它们。强-是保留的同义词,因此保留对象,使对象为零是我们的责任
Ashwin G 2015年

1
@RDC,做什么 default意思?如果我使用@property (nonatomic) NSString *string它是strong?还是assign?因为两者都是默认值。
Iulian Onofrei

40

非原子/原子

  • 非原子比原子快得多
  • 始终使用非原子的,除非您对原子有非常特定的要求,这应该很少见(原子不能保证线程安全-仅在另一个线程同时设置该属性时才停止访问该属性)

强/弱/分配

  • 使用保留对象-尽管关键字“保留”是同义词,但最好改用“强保留”
  • 如果只需要一个不保留对象的指针,请使用函数-避免保留循环(即委托)很有用-当释放对象时,它将自动使指针无效
  • 使用指定的primatives -酷似弱只是它不为零出对象释放(默认设置)时,

(可选的)

复制

  • 用它来创建对象的浅表副本
  • 始终设置要复制的不可变属性的良好实践-因为可变版本可以传递给不可变属性,所以复制将确保您始终处理不可变对象
  • 如果传入一个不可变的对象,它将保留它-如果传入一个可变的对象,它将复制它

只读

  • 使用它来禁用属性的设置(如果存在违规行为,则防止编译代码)
  • 您可以通过直接通过其实例变量更改变量,也可以在getter方法本身内更改getter传递的内容

@Sakthimuthiah是正确的,您必须更正您的答案。
阿德拉·托德里奇

@Sakthimuthiah是不正确的(以及任何其他认为是不正确的人)。原子不会使它成为线程安全的,尽管由于其行为很容易将其误认为。请阅读:stackoverflow.com/questions/12347236/...
克里斯Ĵ

39

据我所知,strong并且retain是同义词,所以它们确实完全相同

然后,weak几乎就像assign,但在它所指向的对象被释放后自动设置为nil。

这意味着,您可以简单地替换它们。

但是,我遇到了一种特殊情况,我必须使用assign而不是weak。假设我们有两个属性delegateAssigndelegateWeak。在这两者中都存储了我们的代表,即通过拥有唯一的强引用来拥有我们。委托正在取消分配,因此我们的-dealloc方法也被调用。

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

委托已经在释放过程中,但是仍然没有完全释放。问题在于weak对他的引用已经无效!属性delegateWeak包含nil,但delegateAssign包含有效的对象(所有属性已经发布并无效,但仍然有效)。

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

这是一个非常特殊的情况,但是它向我们揭示了这些weak变量如何工作以及何时将其无效。



20

Clang关于Objective-C自动参考计数(ARC)的文档清楚地解释了所有权限定符和修饰符:

有四个所有权限定符:

  • __ 自动释放
  • __
  • __ * unsafe_unretained *
  • __

如果类型具有__ 自动释放,__ 或__ 的资格,那么它就是拥有所有权的资格。

然后,对声明的属性有六个所有权修饰符:

  • 分配意味着__ * unsafe_unretained *所有权。
  • 复制意味着__ 强大的所有权,以及setter上复制语义的通常行为。
  • 保留意味着__ 强大的所有权。
  • 暗示__ 所有权。
  • * unsafe_unretained *表示__ * unsafe_unretained *所有权。
  • 意味着__ 所有权

除了weak以外,这些修饰符在非ARC模式下可用。

在语义上,所有权限定词在五个托管操作中具有不同的含义:读取,分配,初始化,销毁和移动,在大多数情况下,我们大多数时候只关心分配操作中的差异。

分配评估赋值运算符时出现。语义因条件而异:

  • 对于__个对象,首先保留新的pointe;第二,左值加载了原始语义;第三,用原始语义将新的pointe存储到左值中。最后,老尖兵被释放。这不是原子执行的;面对并发的加载和存储,必须使用外部同步来使其安全。
  • 对于__个对象,除非新指针是当前正在释放的对象,否则将更新左值以指向新指针,在这种情况下,左值将更新为空指针。对于对象的其他分配,从对象的读取以及新指针的最终释放,这必须原子执行。
  • 对于__ * unsafe_unretained *对象,使用原始语义将新的指针存储到左值中。
  • 对于__ 自动释放对象,将使用原始语义保留,自动释放新指针并将其存储在左值中。

读取,初始化,破坏和移动方面的其他区别,请参阅文档中的第4.2节“语义”


6

为了理解强弱参考,请考虑以下示例,假设我们有一个名为displayLocalVariable的方法。

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

在上述方法中,myName变量的作用域仅限于displayLocalVariable方法,一旦方法完成,保存字符串“ ABC”的myName变量将从内存中释放。

现在,如果我们想在整个视图控制器生命周期中保留myName变量值,该怎么办。为此,我们可以创建名为username的属性,该属性具有对变量myName的强引用(请参见self.username = myName;下面的代码),如下所示,

@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

现在,在上面的代码中,您可以看到myName已分配给self.username,并且self.username具有对myName的强引用(如我们在接口中使用@property在接口中声明的那样)(间接具有对“ ABC”字符串的强引用)。因此,直到self.username处于活动状态时,字符串myName才会从内存中释放。

  • 参考不足

现在考虑将myName分配给一个虚弱引用的dummyName,self.dummyName = myName; 与强引用不同,弱将仅保留myName直到存在对myName的强引用。请参阅以下代码以了解弱引用,

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

在上面的代码中,对myName的引用较弱(即self.dummyName对myName的引用较弱),但对myName没有强引用,因此self.dummyName将无法保存myName值。

现在再次考虑以下代码,

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

在上面的代码中,self.username具有对myName的强引用,因此,即使方法结束后self.dummyName现在也具有myName的值,因为myName具有与其关联的强引用。

现在,每当我们对变量进行强引用时,其保留计数将增加一,并且该变量将不会被释放,保留计数将达到0。

希望这可以帮助。


2

强大:

  • 属性不会销毁,但是只有将属性设置为nil,对象才会被销毁
  • 默认情况下,所有实例变量和局部变量都是强指针。
  • 仅在需要保留对象时才使用Strong。
  • 我们通常对UIViewControllers使用强(UI项的父项)
  • IOS 4(非ARC)我们可以使用保留关键字
  • IOS 5(ARC)我们可以使用强关键字

示例:@property(强,非原子)ViewController * viewController;

@synthesize viewController;

默认情况下自动获取并设置为nil

  • 我们通常对IBOutlets(UIViewController的Childs)使用弱函数并进行委托
  • 与分配相同,没有保留或释放

示例:@属性(弱,非原子)IBOutlet UIButton * myButton;

@synthesize myButton;


1

强和保留之间的区别:

  • 在iOS4中,强等于保留
  • 这意味着您拥有该对象并将其保留在堆中,直到不再指向它为止
  • 如果您写保留,它将自动像强

弱和赋值之间的区别:

  • “弱”引用是您不会保留的引用,只要他人强烈指出,您就保留该引用
  • 当对象被“取消分配”时,弱指针将自动设置为nil
  • “赋值”属性的属性告诉编译器如何综合属性的setter实现
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.