美文网首页
OC @Property属性

OC @Property属性

作者: Fisland_枫 | 来源:发表于2018-12-17 15:30 被阅读5次

[TOC]

本质是什么

实际上@property = 实例变量 + get方法 + set方法。也就是说属性
@property name: setter方法+getter方法+_name

自动合成

定义一个property,在编译期间,编译器会生成实例变量,getter方法、setter方法,这些方法是通过自动合成(autosynthesize)的方式生成并添加到类中。
实际上,一个类经过编译后,会生成变量列表ivar_list,方法列表,method_list。每添加一个属性,在变量列表ivar_list会添加对应的变量,如_name,在方法列表method_list中会添加对应的setter和getter方法。

@synthesize name = _name;

手动合成

那么有自动合成,就有手动合成。
手动合成代码

@dynamic sex;

这样就告诉编译器,sex属性的实例变量,getter方法、setter方法都由开发者自己添加

//下面代码不添加,在使用该属性时候,程序会崩溃
@interface Student : NSObject
{
    NSString *_sex;
}

@property (nonatomic, copy) NSString *name;

@property (nonatomic, copy) NSString *sex;

@end

整体代码

@property (nonatomic,copy) NSString *name;///< name
@end

@implementation ViewController
/*
    两个一起写会报错,因为重写了get和set方法,编译器认为开发者想手动管理@property,此时会将@property作为@dynamic来处理
    因此也就不会自动生成变量。解决方法,显示的将属性和一个变量绑定:@synthesize name = _name;
    @synthesize name = _name;
*/
@synthesize name = _name;
- (void)setName:(NSString *)name{
    _name = name;
}

//get 不能使用self. 会造成死循环
-(NSString *)name{
    return _name;
//    return self.name;  // 错误的写法,会造成死循环

}

@property修饰符

  1. 修饰符的种类
    1. 原子性 -nonatomic, atomic
    2. 读写权限 -readwrite和readonly
    3. 内存管理 - assign,strong,weak,copy,unsafe_unretained
    4. set,get方法
  2. weak和assign的区别
    1. Weak修饰对象,对象释放后,引用计数为0,对象会被置为nil。
    2. assign修饰基本数据类型,如果用assign修饰对象,对象释放后,引用计数为0后,对象会变成野指针,容易崩溃。为什么基本数据类型不会,因为基本数据类型是在栈上面,不是在堆上面的。
  3. copy和strong
    1. 不可变使用copy,可变使用strong

不可变使用strong的例子

@property (nonatomic, strong) NSString *strongStr;
- (void)testStrCopy {
    NSString *tempStr = @"123";
    NSMutableString *mutString = [NSMutableString stringWithString:tempStr];
    self.strongStr = mutString;  // 子类初始化父类
    NSLog(@"self str = %p  mutStr = %p",self.strongStr,mutString);   // 两者指向的地址是一样的
    [mutString insertString:@"456" atIndex:0];
    NSLog(@"self str = %@  mutStr = %@",self.strongStr,mutString);  // 两者的值都会改变,不可变对象的值被改变
    /*
     self str = 0x281806520  mutStr = 0x281806520
     self str = 456123  mutStr = 456123
     */
}

可变使用copy的例子

@property (nonatomic, copy) NSMutableString *mutString;
- (void)testStrCopy {
    NSString *str = @"123";
    self.mutString = [NSMutableString stringWithString:str];
    /*
    // 首先声明一个临时变量 NSMutableString *tempString = [NSMutableString stringWithString:str]; 
    // 将该临时变量copy,赋值给self.mutString self.mutString = [tempString copy];
    通过[tempString copy]得到的self.mutString是一个不可变对象
    */
    NSLog(@"str = %p self.mutString = %p",str,self.mutString); // 两者的地址不一样
    [self.mutString appendString:@"456"]; // 会崩溃,因为此时self.mutArray是NSString类型,是不可变对象
}

可变对象的copy、mutableCopy,可以看到,只要是可变对象,无论是集合对象,还是非集合对象,copy和mutableCopy都是深拷贝。

- (void)testMutableCopy
{
    NSMutableString *str1 = [NSMutableString stringWithString:@"abc"];
    NSString *str2 = [str1 copy];
    NSMutableString *str3 = [str1 mutableCopy];
    NSLog(@"str1 = %p str2 = %p str3 = %p",str1,str2,str3);
    
    NSMutableArray *array1 = [NSMutableArray arrayWithObjects:@"a",@"b", nil];
    NSArray *array2 = [array1 copy];
    NSMutableArray *array3 = [array1 mutableCopy];
    NSLog(@"array1 = %p array2 = %p array3 = %p",array1,array2,array3);
}

2018-12-13 19:12:44.287404+0800 testcopy[2654:1672606] str1 = 0x28020fba0 str2 = 0x92e1881c542bdf17 str3 = 0x28020f780
2018-12-13 19:12:44.287475+0800 testcopy[2654:1672606] array1 = 0x28020f8d0 array2 = 0x280c5e780 array3 = 0x28020fa20

不可变对象的copy、mutableCopy,不可变对象的copy是浅拷贝,mutableCopy是深拷贝。以NSString和NSArray为例,测试代码如下:

- (void)testCopy
{
    NSString *str1 = @"123";
    NSString *str2 = [str1 copy];
    NSMutableString *str3 = [str1 mutableCopy];
    NSLog(@"str1 = %p str2 = %p str3 = %p",str1,str2,str3);
    
    NSArray *array1 = @[@"1",@"2"];
    NSArray *array2 = [array1 copy];
    NSMutableArray *array3 = [array1 mutableCopy];
    NSLog(@"array1 = %p array2 = %p array3 = %p",array1,array2,array3);
}
2018-12-13 19:14:27.982467+0800 testcopy[2656:1673120] str1 = 0x102fc8078 str2 = 0x102fc8078 str3 = 0x280558f00
2018-12-13 19:14:27.982529+0800 testcopy[2656:1673120] array1 = 0x280b09ea0 array2 = 0x280b09ea0 array3 = 0x280558fc0

自定义对象如何支持copy:

自定义对象遵守NSCopying协议,且实现copyWithZone方法,NSCopying是系统方法,直接使用即可。

@interface Student : NSObject <NSCopying> 
{ 
    NSString *_sex; 
} 
@property (atomic, copy) NSString *name; 
@property (nonatomic, copy) NSString *sex; 
@property (nonatomic, assign) int age; @end


- (instancetype)initWithName:(NSString *)name age:(int)age sex:(NSString *)sex
{
    if(self = [super init]){
        self.name = name;
        _sex = sex;
        self.age = age;
    }
    return self;
}

- (instancetype)copyWithZone:(NSZone *)zone
{
    // 注意,copy的是自己,因此使用自己的属性
    Student *stu = [[Student allocWithZone:zone] initWithName:self.name age:self.age sex:_sex];
    return stu;
}

输出

- (void)testStudent
{
    Student *stu1 = [[Student alloc] initWithName:@"Wang" age:18 sex:@"male"];
    Student *stu2 = [stu1 copy];
    NSLog(@"stu1 = %p stu2 = %p",stu1,stu2);
}
stu1 = 0x600003a41e60 stu2 = 0x600003a41fc0
//深复制,因为是内存复制,copyWithZone,而不是直接内存地址指向。

来源:iOS面试之@property

相关文章

  • iOS属性

    什么是属性 属性是OC语言中的一个机制,我们在OC中用@property来声明一个属性,其实@property是一...

  • iOS基础之Objective-C(一)

    OC面向对象新增语法:1、属性生成器: @property //声明属性例:@property (nonatomi...

  • @property参数

    ARC 1>OC对象类型 @property(nonatomic,strong)类名 *属性名 @property...

  • OC @Property属性

    [TOC] 本质是什么 实际上@property = 实例变量 + get方法 + set方法。也就是说属性@pr...

  • iOS属性

    OC属性 在OC中用@property来声明一个属性,其实@property是一个语法糖,编译器会自动为实力变量生...

  • 52个有效方法(6) - 理解“属性”这一概念

    “属性”(property)是OC的一项特性,用于封装对象中的数据。 @property @Property是声明...

  • 五、 OC底层面试题

    1.属性&成员变量&属性的区别 属性(property):在OC中是通过@property开头定义,且是带下划线成...

  • iOS 编写高质量代码(二)

    这篇将从面向对象的角度分析如何提高OC的代码质量。 一、理解“ 属性 ”这一概念 属性(@property)是OC...

  • Property cannot be marked @objc

    oc调用swift, 访问Bool属性isRegist时: 报错: Property cannot be mark...

  • oc@property属性

    assign: 简单的赋值 不会更改索引计数(Reference counting),这个属性一般用来处理基础类型...

网友评论

      本文标题:OC @Property属性

      本文链接:https://www.haomeiwen.com/subject/fdcckqtx.html