理解 Objective-c "属性"

理解 Objective-c "属性"

@property 是OC中能够快速定义一个属性的关键字,如下我们定义一个属性。

@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语法指定实例变量的名字。

@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 这些特性决定了存方法如何处理与其相关的内存管理问题

  • 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过程

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

atomic 和nonatomic

  • 如果不声明默认是atomic,atomic属性的存方法并不会对多线程下的安全有太大帮助,所以一般用nonatomic,而且atomic会影响性能。(确保线程安全必定会有额外开销)
原文地址:https://www.cnblogs.com/code-changeworld/p/4782705.html