理解 Objective-c "属性"

理解 Objective-c "属性"

@property 是OC中可以快速定义一个属性的关键字,以下咱们定义一个属性。objective-c

@property   NSString        *String;

这样咱们就可使用这个属性安全

属性的实质

  • 在属性被加入OC之前咱们每次声明一个实例变量都要本身声明并实现存取方法
//
// Created by chao on 15/8/29.
// Copyright (c) 2015 ___FULLUSERNAME___. All rights reserved.
//

#import <Foundation/Foundation.h>
@interface Person : NSObject{
    NSString *firstName;
    NSString *lastName;
}

- (void)setFirstName:(NSString *)first;
- (NSString *)firstName;
- (void)setLastName:(NSString *)last;
- (NSString *)lastName;
@end
//在.m文件里实现

#import "Person.h"
@implementation Person {
}

- (void)setFirstName:(NSString *)first {
    firstName = [first copy];
}

- (NSString *)firstName {
    return  firstName;
}

- (void)setLastName:(NSString *)last {
    lastName = [last copy];
}

- (NSString *)lastName {
    return lastName;
}

@end

如今有了@property只要简单的声明一下就可让编译器替咱们作以上哪些繁杂的工做。多线程

@property   NSStrinng   *firstNmae;
@property   NSString    *lastName;
  • 声明属性 编译器除了生成存取方法代码外,还要自动向类中添加适当类型的实例变量。

编译器会自动在属性名以前添加下划线,一次做为实例变量的名字,在上面的声明中会生成两个实例变量
_firstNam, _lastName.咱们也可使用@synthesize语法指定实例变量的名字。app

@synthesize firstName   =   _myFirstName; //使用指定的实例变量名称
@synthesize lastName = _myLastName;//若是没有特殊须要尽可能使用系统默认的名称
  • 若是不想令编译器合成存取方法, 则能够本身实现,若是只实现了其中一个存取方法, 则另一个仍是会由编译器从新合成,你可使用@dynamic 关键字阻止编译器自动合成存取方法。

@dynamic关键字

@property   NSStrinng   *firstNmae;
@property   NSStrinng   *firstNmae;

@dynamic    firstName, lastname;    //编译器不会自动为这两个属性合成存取方法,或实例变量。

属性的特性

存取类型

  • readwrite (默认)编译器自动建立存方法和取方法
  • readonly 不生成存方法,若是一个属性不容许修改则能够将其声明为存方法。

在为以上类添加一个只读的ID和weight属性。性能

@property   (readonly)  NSInteger   ID;
@property   (readwrite) NSInteger   height;

若是咱们这程序中试图修改person 的ID属性编译器就会报错优化

readonly error

生命周期类型(内存管理类型)

生命周期类型的特性包括, assign, strong, weak和copy 这些特性决定了存方法如何处理与其相关的内存管理问题atom

  • assign (默认)最简单的,存入的值会将传入的值直接赋给实例变量。
@property   (assign)    NSInteger   ID;
这段代码等同于实现了一下存方法
- (void)setID:(NSInteger)d {
    ID = d;
 }
  • strong 特性要求保留传入的对象,并放弃原有对象(若是原有对象不在有其余拥有方,就会被释放)。凡是指向对象的实例变量,一般都应该使用strong
  • weak 要求不保留传入的对象,相应的存取方法会将传入的对象直接赋给实例变量。若是该对象被释放,那么相应的实例变量会呗自动置nil
  • copy 特性要求拷贝传入对象,并将新对象赋给实例变量。

copy 详解

看了不少博客讲解的copy都只是简单的说了一下,copy特性要求拷贝传入对象。并无进行深刻的讲解,好比为何要copy传入对象,下面我写一下我本身对copy的理解线程

  1. 在OC中有些类会有特定的可修改的子类,好比 像NSString 和 NSMutableString 这些类咱们日常使用时通常都声明为copy。像下面咱们定义一个NSString 属性,可是给其存方法传入 NSMutableString 是合法的,声明为 copy,就能够避免修改 原对象对实例变量的影响
@property   (strong)    NSString        *firstName;
@property   (copy)  NSString        *lastName;
NSMutableString  *name = [[NSMutable alloc] initWithString:@"Li"];
[person     setFirstNmae:name];
[person setLastName:name];//这样修改name 不会对实例变量产生影响。
//看如下程序的输出
 NSMutableString  *firstName = [NSMutableString stringWithString:@"Zhang"];
 NSMutableString  *lastName  = [NSMutableString stringWithString:@"San"];
person.firstName = firstName;
person.lastName = lastName;
NSLog(@"修改前的 :%@%@", person.firstName, person.lastName);
[firstName appendString:@"fe"];
[lastName appendString:@"aefa"];
NSLog(@"修改后的 :%@%@", person.firstName, person.lastName);
NSLog(@"%@%@", firstName, lastName);

copy mark

2.若是传入的对象是不可修改的,copy方法实际是在调用copyWithZone:通常咱们自定义的对象若是要求copy,应该重写 copyWithZone:方法从而优化copy过程code

- (id)copyWithZond {
    return self;
}
  1. copy返回的值老是不可修改的,若是须要copy出可修改的对象,须要使用对应的mutableCopy方法

atomic 和nonatomic

  • 若是不声明默认是atomic,atomic属性的存方法并不会对多线程下的安全有太大帮助,因此通常用nonatomic,并且atomic会影响性能。(确保线程安全一定会有额外开销)
相关文章
相关标签/搜索