理解 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會影響性能。(確保線程安全一定會有額外開銷)
相關文章
相關標籤/搜索