关于ios:为什么类对象是retain的属性属性而不是copy?

Why are class objects the property attribute of retain and not copy?

本问题已经有最佳答案,请猛点这里访问。

我试图将自定义对象传递给下一个视图控制器,但遇到了这个错误-[ClassName copyWithZone:] unrecognized selector sent to instance

1
2
3
4
5
6
7
8
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {

    if ([segue.identifier isEqualToString:@"attemptDetails"])
    {
        ResultsVC *vc = segue.destinationViewController;
        vc.selectedEntry = selectedEntry;
    }
}

@property (nonatomic, retain) ClassName *selectedEntry; //Why is it retain and not copy?

我仍然很困惑于属性属性,以及为什么某些类型使用某些属性,比如nsstring使用(nonatomic, copy),cllocationCoordinate2d使用(nonatomic, readonly)

有人能解释或链接一个引用给我每个属性是如何工作的吗?非常感谢!


我读过几篇关于内存管理的好文章。根据Rypress

retain属性:retain属性是strong的手动retain发布版本,它具有完全相同的效果:声明所分配值的所有权。您不应该在自动引用计数的环境中使用它。

复制属性:复制属性是强的替代。它不是取得现有对象的所有权,而是创建一个您分配给该属性的任何内容的副本,然后取得该对象的所有权。只有符合nscopying协议的对象才能使用此属性。

甚至我也经历了stackoverflow的一些良好链接。Joshua Nozzi的回答很好地解释了保留与复制的关系。

保留与复制声明的属性默认情况下使用保留(这样您可以完全忽略它),并将自动管理对象的引用计数,无论是将另一个对象分配给该属性还是将其设置为nil;使用复制自动发送新分配的对象A-复制消息(这将创建传递对象的副本)并将该副本分配给属性-在某些情况下是有用的(甚至是必需的),这些情况下,分配的对象在设置为其他对象的属性之后可能会被修改(这意味着修改/变异也将应用于该属性)。

在这里也找到了很好的例子。

代码:

1
2
3
4
5
6
7
8
9
10
NSMutableArray *array = [[NSMutableArray alloc] initWithObjects:@"First",@"Second", nil];
    NSMutableArray *copiedArray = [array mutableCopy];
    NSMutableArray *retainedArray = [array retain];

    [retainedArray addObject:@"Retained Third"];
    [copiedArray addObject:@"Copied Third"];

    NSLog(@"array = %@",array);
    NSLog(@"Retained Array = %@",retainedArray);
    NSLog(@"Copied Array = %@",copiedArray);

输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
array = (
    First,
    Second,
   "Retained Third"
)
2013-12-19 17:15:49.380 RetainVsCopy[2876:c07] Retained Array = (
    First,
    Second,
   "Retained Third"
)
2013-12-19 17:15:49.381 RetainVsCopy[2876:c07] Copied Array = (
    First,
    Second,
   "Copied Third"
)

请参见,数组和保留数组都具有相同的内容。这是因为两者都指向相同的内存/实例/对象。其中as复制数组的内容不同。这是因为copy创建了一个单独的实例。


对属性的解释有很多描述,

参考链接,

目标C弧:强vs保留和弱vs分配

https://stackoverflow.com/a/4511004/4294543

@在目标C中拥有、保留、分配、复制、非原子

简而言之,我的理解是,

保留:它在处理创建的对象,只增加引用计数。

  • 在本例中,您已经有了模型类对象,因此不需要复制第二个vc属性,只需要将其保留到第二个vc属性。

复制:您分配给属性的值也可以复制并用于其他目的(对象可变时创建对象的浅副本,完成后需要释放对象)。

非原子:线程访问速度更快,但不能同时访问和更改属性。

只读:不能直接分配属性new值。

即使我在我的项目中处理过你的案子,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#import"ViewController.h"
#import"TestViewController.h"
#import"CustomClass.h"
@interface ViewController (){

    CustomClass *classT;
}

@end
@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    classT = [[CustomClass alloc]init];
    classT.test = YES;

}
- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}
- (IBAction)btn:(id)sender {
    TestViewController * vc = [self.storyboard instantiateViewControllerWithIdentifier:@"TestViewController"];
    vc.className = classT;
    [self presentViewController:vc animated:YES completion:nil];
}
@end




#import <UIKit/UIKit.h>
#import"CustomClass.h"

@interface TestViewController : UIViewController


@property (nonatomic,retain) CustomClass *className; // Work as i said

//@property (nonatomic,copy) CustomClass *className; // Makes a copy of an object, and returns it with retain count of 1. If you copy an object, you own the copy. This applies to any method that contains the word copy where"copy" refers to the object being returned thats why here you will get crash


@end


在目标C中,您会发现每个类背后实际上都有一个结构。属性是在结构、getter和setter中创建值的快捷方式。例如:

1
2
3
4
5
@interface MyClass

@property id myValue;

@end

将创造:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@interface MyClass {
   id _myValue;
}

@property id myValue;

@end

@implementation

- (id)myValue {
    return _myValue;
}
- (void)setMyValue:(id)myValue {
    _myValue = myValue;
}

@end

现在,这些标志(如retaincopy向setter和getter添加了额外的逻辑。使用copy将实际创建一个setter,如下所示:

1
2
3
- (void)setMyValue:(id)myValue {
    _myValue = [myValue copy];
}

这意味着该值必须实现copy方法。因为你的物体没有,它就崩溃了。

为什么使用拷贝是为了安全。这对于字符串这样的东西很少重要,但是对于数组这样的东西很重要。例如,您创建了一个属性@property NSArray *myArray;,它期望一个不可变的数组,但问题是您也可以设置一个可变的数组:myClassInstance.myArray = [[NSMutableArray alloc] init];。现在,2个模块可以访问相同的可变数组。因此,如果第一个对象开始修改数组,而另一个对象期望数组始终相同,那么您可能会发现一些问题。例如,MyClass实例可以将它用作表视图的数据源,并且在某一点上,数组会发生变化,但单元格不会被添加/删除,表视图会导致崩溃。

老实说,您可以简单地将所有这些都作为默认值,只有在您真正需要时才修改它们。无论如何,像上面这样的情况是不太可能发生的。