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

时间:2012-01-19 14:27:46

标签: ios objective-c ios5 properties automatic-ref-counting

ARC引入的属性有两个新的内存管理属性,strongweak

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

根据我的理解,这里唯一的区别是weak会将nil分配给指针,而assign则不会,这意味着当我发送消息时程序会崩溃一旦它被释放就指向指针。但是,如果我使用weak,则不会发生这种情况,因为发送给nil的邮件将不会执行任何操作。

我不知道strongretain之间存在任何差异。

我有什么理由在新项目中使用assignretain,还是被弃用?

8 个答案:

答案 0 :(得分:594)

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

  1. atomic // default
  2. 非原子
  3. strong = retain // default
  4. 保留
  5. assign // default
  6. unsafe_unretained
  7. 复制
  8. 只读
  9. readwrite // default
  10. 下面是详细的文章链接,您可以在其中找到上述所有属性,这些内容肯定会对您有所帮助。 非常感谢所有在这里给出最佳答案的人!!

      

    Variable property attributes or Modifiers in iOS

    1.strong(iOS4 =保留)

    • 它说“将它保留在堆中,直到我不再指向它”
    • 换句话说“我是主人,你不能在与保留相同的目标之前解除这个”
    • 只有在需要保留对象时才使用strong。
    • 默认情况下,所有实例变量和局部变量都是强指针。
    • 我们通常对UIViewControllers(UI项目的父母)使用strong
    • strong与ARC一起使用,它基本上可以帮助您,而不必担心对象的保留计数。 ARC完成后会自动为您释放它。使用关键字strong表示您拥有该对象。

    示例:

    @property (strong, nonatomic) ViewController *viewController;
    
    @synthesize viewController;
    

    <强> 2.weak      -

    • 它说“只要别人强烈指出它就保持这个”
    • 与分配相同,不保留或释放
    • “弱”引用是您不保留的引用。
    • 我们通常对IBOutlets使用weak(UIViewController的Childs)。这是有效的,因为只要父对象存在,子对象才需要存在。
    • 弱引用是一种引用,它不保护引用的对象不被垃圾收集器收集。
    • 弱基本上是指定的,一个没有保留的财产。除了取消分配对象的时间之外,弱指针自动设置为nil

    示例:

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

    强大&amp;弱解释,Thanks to BJ Homer

      

    想象一下,我们的对象是一只狗,狗想要逃跑(是的   解除分配)。

         

    强壮的指针就像是狗的皮带。只要你有   皮带附着在狗身上,狗不会逃跑。如果五个人   将他们的皮带系在一只狗上,(一个物体的五个强指针),   然后狗不会逃跑,直到所有五个皮带脱落。

         另一方面,弱点就像小孩子指着的那样   狗,说“看!一只狗!”只要狗还在上   皮带,小孩子仍然可以看到狗,他们仍然会指出   它。然而,一旦所有的皮带脱落,狗就跑了   不管有多少小孩指着它。

         

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

    当我们使用弱者时?

    你唯一想要使用弱的方法是,如果你想避免保留周期 (例如,父母保留孩子,孩子保留父母,所以两者都没有被释放)。

    3.retain = strong

    • 保留,旧值被释放并且被分配保留指定应该发送新值
    • 保留作业并发送旧值-release
    • 保留与强者相同。
    • apple说如果你写保留它会自动转换/工作就像强大。
    • 像“alloc”这样的方法包含一个隐含的“retain”

    示例:

    @property (nonatomic, retain) NSString *name;
    
    @synthesize name;
    

    4.assign

    • assign是默认值,只是执行变量赋值
    • assign是一个属性属性,告诉编译器如何合成属性的setter实现
    • 我会使用assign表示C原语属性,而weak表示弱对Objective-C对象的引用。

    示例:

    @property (nonatomic, assign) NSString *address;
    
    @synthesize address;
    

答案 1 :(得分:228)

来自Transitioning to ARC Release Notes(属性属性部分中的示例)。

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

@property(strong) MyClass *myObject;

因此strong与属性声明中的retain相同。

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

答案 2 :(得分:39)

据我所知,strongretain是同义词,因此完全相同

然后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变量如何工作以及它们何时无效。

答案 3 :(得分:38)

非原子/原子

  • 非原子比原子快得多
  • 总是使用非原子,除非你有一个非常特殊的原子要求,这应该是罕见的(原子不能保证线程安全 - 只有当它被另一个线程同时设置时才会停止访问该属性)< / LI>

强/弱/分配

  • 使用 strong 来保留对象 - 虽然关键字retain是同义词,但最好使用strong而不是
  • 如果你只想要一个指向对象的指针而不保留它,那么
  • 使用 weak - 对于避免保留周期(即委托)很有用 - 当对象被释放时它会自动将指针弄清楚
  • 使用分配作为灵长类动物 - 完全像弱者一样,除非它在释放时没有释放对象(默认设置)

(可选)

复制

  • 用它来创建对象的浅表副本
  • 总是将不可变属性设置为复制的好习惯 - 因为可变版本可以传递到不可变属性中,复制将确保您始终处理不可变对象
  • 如果传入一个不可变对象,它将保留它 - 如果传入一个可变对象,它将复制它

只读

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

答案 4 :(得分:20)

Clang关于Objective-C Automatic Reference Counting (ARC)的文件清楚地解释了所有权限定符和修饰符:

  

有四个所有权限定符:

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

如果类型符合条件,则该类型具有非平凡的所有权限定条件   __ 自动释放,__ 或__

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

  
      
  • assign 暗示__ * unsafe_unretained *所有权。
  •   
  • copy 意味着__ 所有权,以及setter上复制语义的常见行为。
  •   
  • 保留表示__ 所有权。
  •   
  • strong 意味着__ 所有权。
  •   
  • * unsafe_unretained *暗示__ * unsafe_unretained * ownership。
  •   
  • 意味着__ 所有权。
  •   
     

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

语义明智,所有权限定符在五个管理操作中具有不同的含义:阅读,分配,初始化,销毁和移动,其中大多数时候我们只关心分配操作的差异。

  评估赋值运算符时会发生

赋值。该   语义因资格而异:

     
      
  • 对于__ 对象,首先保留新的指针;第二,左值加载了原始语义;第三,新的指针被存储到具有原始语义的左值中;最后,老指针被释放了。这不是原子地执行的;必须使用外部同步,以便在并发加载和存储时使其安全。
  •   
  • 对于__ 对象,左值更新为指向新的指针,除非新指针是当前正在进行解除分配的对象,在这种情况下,左值更新为空指针。这必须相对于对象的其他赋值,从对象读取以及新指针的最终版本以原子方式执行。
  •   
  • 对于__ * unsafe_unretained *对象,新的指针对象使用原始语义存储到左值中。
  •   
  • 对于__ autoreleasing 对象,新的指针对象将被保留,自动释放,并使用原始语义存储到左值中。
  •   

阅读,初始,毁灭和移动的另一个区别,请参阅Section 4.2 Semantics in the document

答案 5 :(得分:3)

要了解强弱参考,请考虑以下示例, 假设我们有一个名为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具有与其关联的强引用。

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

希望这会有所帮助。

答案 6 :(得分:2)

强:

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

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

@synthesize viewController;

默认自动获取并设置为nil

  • 我们通常对IBOutlets使用weak(UIViewController的Childs)和委托
  • 与分配相同,不保留或释放

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

@synthesize myButton;

答案 7 :(得分:1)

强者和保留者之间的区别:

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

弱与分配之间的差异:

  • “弱”参考是您不保留的参考,只要其他人强烈指出,您就会保留该参考
  • 当对象被“解除分配”时,弱指针自动设置为nil
  • “assign”属性属性告诉编译器如何合成属性的setter实现