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

Jak*_*old 365 properties objective-c ios ios5 automatic-ref-counting

有由ARC推出性能的两种新的内存管理的属性,strongweak.

除了copy显然是完全不同的东西之外,vs vs 之间有什么区别吗?strongretainweakassign

根据我的理解,这里唯一的区别是weak将分配nil给指针,而assign不会,这意味着程序将在指针释放后向指针发送消息时崩溃.但是,如果我使用weak,这将永远不会发生,因为发送消息nil不会做任何事情.

我不知道strong和之间有什么不同retain.

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

swi*_*Boy 603

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

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

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

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

1.strong(iOS4 =保留)

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

例:

@property (strong, nonatomic) ViewController *viewController;

@synthesize viewController;
Run Code Online (Sandbox Code Playgroud)

2.weak -

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

示例:

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

@synthesize myButton;
Run Code Online (Sandbox Code Playgroud)

强烈而微弱的解释,感谢BJ荷马:

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

强壮的指针就像是狗的皮带.只要你的皮带附着在狗身上,狗就不会逃跑.如果五个人将他们的皮带连接到一只狗,(五个强指针指向一个物体),那么在所有五个皮带脱落之前,狗不会逃跑.

另一方面,弱点就像小孩子指着那只狗说"看!一只狗!" 只要狗仍然在皮带上,小孩子仍然可以看到狗,他们仍然会指向它.然而,一旦所有的皮带脱落,无论有多少小孩指着它,狗都会跑开.

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

当我们使用弱者?

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

3.retain = strong

  • 它被保留,旧值被释放并且被赋值保留指定应该发送新值
  • 保留分配和旧值发送 - 释放
  • 保留与强者一样.
  • 苹果说,如果你写保留它将自动转换/工作只有强大.
  • 像"alloc"这样的方法包含一个隐含的"保留"

例:

@property (nonatomic, retain) NSString *name;

@synthesize name;
Run Code Online (Sandbox Code Playgroud)

4.assign

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

例:

@property (nonatomic, assign) NSString *address;

@synthesize address;
Run Code Online (Sandbox Code Playgroud)

  • 2."弱引用是一个不能保护被引用对象不被垃圾收集器收集的引用" - 目标c中没有垃圾收集器这样的东西; (5认同)
  • @RDC,“默认”是什么意思?如果我使用 `@property (nonatomic) NSString *string` 它是 `strong`?还是“赋值”?因为两者都是默认值。 (2认同)

Jer*_*myP 229

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

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

@property(strong) MyClass *myObject;
Run Code Online (Sandbox Code Playgroud)

因此strongretain财产声明中的相同.

对于ARC项目,我将使用strong而不是retain,我将assign用于C原始属性和weak对Objective-C对象的弱引用.

  • 事实上,在ARC下,使用`assign`作为对象是一个编译错误.如果你不想保留属性,你必须使用`weak`或`unsafe_unretained`(显然是不安全的). (11认同)
  • @Pascal:在os不是5.0或更高版本的部署目标中不允许弱引用.因此对于较旧的项目,您仍然可以使用assign,但如果您转移到较新的版本,则必须切换到weak (8认同)
  • 在部署目标4.0的ARC项目中,`assign`编译得很好. (5认同)
  • @JeremyP是的,你的答案是正确的.我对@Mattia做出了反应.我指出`assign`在某些情况下仍然有效. (3认同)

Tri*_*ops 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];
}
Run Code Online (Sandbox Code Playgroud)

委托已经处于释放过程中,但仍未完全取消分配.问题是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.
}
Run Code Online (Sandbox Code Playgroud)

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


Vad*_*off 39

非原子/原子

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

强/弱/分配

  • 使用strong来保留对象 - 尽管关键字retain是同义词,但最好使用strong
  • 如果你只想要一个指向对象的指针而不保留它,则使用weak - 对于避免保留周期(即委托)很有用 - 当对象被释放时它会自动将指针弄为零
  • 使用赋值为primatives - 完全像weak一样,除了它释放时不会释放对象(默认设置)

(可选的)

复制

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

只读

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

  • 原子属性属性保证线程安全 (3认同)

Min*_*ing 20

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

有四个所有权限定符:

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

如果类型具有__ autoreleasing,__ strong或__ weak限定,则该类型具有非平凡的所有权限定.

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

  • assign暗示__*unsafe_unretained*所有权.
  • copy意味着__ 主权,以及setter上复制语义的通常行为.
  • 保留意味着__ 强大的所有权.
  • 强烈意味着__ 强大的所有权.
  • *unsafe_unretained*暗示__*unsafe_unretained*所有权.
  • 意味着__ 所有权.

弱点外,这些修饰符可在非ARC模式下使用.

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

分配评估赋值运算符时出现.语义因资格而异:

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

阅读,初始化,销毁和移动的另一个区别,请参阅文档中的第4.2节语义.


Mah*_*ale 6

要理解强引用和弱引用,请考虑以下示例,假设我们有名为 displayLocalVariable 的方法。

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

在上述方法中,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
Run Code Online (Sandbox Code Playgroud)

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

  • 弱参考

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

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

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

现在再次考虑下面的代码,

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

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

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

希望这可以帮助。


归档时间:

查看次数:

192118 次

最近记录:

7 年 前