Objective-C知識點(diǎn)雜集一

第一部分

  • 類的@interface、@implementation描述
  • 類方法和實(shí)例方法
  • 初步理解alloc和init
  • 初步理解聲明一個對象(實(shí)例)
  • setter方法和getter方法
  • 基本數(shù)據(jù)類型
  • 限定詞:long、long long、short、unsigned、signed
  • #import <>和""的區(qū)別

類的@interface、@implementation描述

@interface接口部分用于描述類和類的方法

@implementation實(shí)現(xiàn)部分用于描述數(shù)據(jù)(類對象的實(shí)例變量存儲的數(shù)據(jù)),并實(shí)現(xiàn)在接口中聲明方法的實(shí)際代碼。也可以在interface(接口)部分為類聲明實(shí)例變量。


類方法和實(shí)例方法

開頭的負(fù)號(-)表示該方法是一個實(shí)例方法;實(shí)例方法能夠?qū)︻惖膶?shí)例執(zhí)行一些操作,例如,設(shè)置值、檢索值和顯示值等。

開頭的正號(+)表示這是一個類方法;類方法是對類本身執(zhí)行某些操作的方法,例如,創(chuàng)建類的新實(shí)例。

實(shí)例方法總是可以直接訪問它的實(shí)例變量。然而,類方法不能,因?yàn)樗惶幚肀旧?,并不處理任何?shí)例。


初步理解alloc和init

alloc是allocate(vt.分配,分派; 把…撥給)的縮寫。作用是為新創(chuàng)建的對象(實(shí)例)分配內(nèi)存。alloc方法保證對象的所有實(shí)例變量都變成初始狀態(tài)。然而,這并不意味著該對象已經(jīng)進(jìn)行了適當(dāng)?shù)某跏蓟?,從而可以使用。在?chuàng)建對象之后,還必須對它初始化。

init方法用于初始化類的實(shí)例變量。

理解:alloc可以使實(shí)例變量指定為0或者是nil,但是對象還是沒有被正確的初始化,所以必須使用init來初始化新創(chuàng)建的對象。


初步理解聲明一個對象(實(shí)例)

聲明一個對象:Fraction *myFraction;

myFraction前的星號()表明myFraction是Fraction對象的引用(或指針)。變量myFraction實(shí)際上并不儲存Fraction的數(shù)據(jù),而是存儲了一個引用(其實(shí)是內(nèi)存地址),表明對象數(shù)據(jù)在內(nèi)存中的位置。在聲明myFraction時,它的值時未定義的,它沒有被設(shè)定為任何值,并且沒有默認(rèn)值*。在概念上,我們可以認(rèn)為myFraction是一個能夠容納值的盒子。在初始化盒子時包含了一些未定義的值,它并沒有被指定任何值。

如果你創(chuàng)建一個新對象(例如,使用alloc),就會在內(nèi)存中為它保留足夠的空間用于存儲對象數(shù)據(jù),這包括它的實(shí)例變量空間,再另外預(yù)留了一些。通常,alloc會返回存儲數(shù)據(jù)的位置(對數(shù)據(jù)的引用),并賦給變量myFraction。


setter方法和getter方法

設(shè)值方法和取值方法通常稱為訪問器(accessor)方法。


基本數(shù)據(jù)類型
  • oc中的基本數(shù)據(jù)類型有:int、float、double、char、long、double。

  • 在oc中,任何數(shù)字、單個字符或者字符串通常稱為常量。例如,數(shù)字58是一個常量整數(shù)值。字符串@"aaaaaa"表示一個常量字符串對象。表達(dá)式 @5 表示一個常量數(shù)字對象。

  • 每個值無論是字符、整數(shù)還是浮點(diǎn)數(shù)字,都有其對應(yīng)的值域。這個值域與系統(tǒng)為特定類型的值分配的內(nèi)存量有關(guān)。一般來說,在語言中沒有規(guī)定這個量,它通常依賴于所運(yùn)行的計算機(jī)。因此,叫做設(shè)備或機(jī)器相關(guān)量。例如,一個整數(shù)可以在計算機(jī)上占用32位。

  • 要區(qū)分浮點(diǎn)常量,可以看它是否包含小數(shù)點(diǎn)。float類型和double類型(浮點(diǎn)常量),可以存儲科學(xué)計數(shù)法數(shù)字。例如,1.7e4、17e-1就是使用這種計數(shù)法來表示的浮點(diǎn)數(shù),它表示值1.710^4、1710^-1。

  • 在計算機(jī)內(nèi)存中,不能精確的表示一些浮點(diǎn)值。


限定詞:long、long long、short、unsigned、signed
  • 如果直接把long放在int前面,那么所聲明的整型變量在某些計算機(jī)上具有擴(kuò)展的值域。long變量的具體范圍也是有具體的計算機(jī)系統(tǒng)決定。

long int a;long long int;long double;

  • 把限定詞short放在int前,表示要聲明的整型變量用來存儲相當(dāng)小的整數(shù)。之所以使用short變量,主要是出于節(jié)約內(nèi)存空間的考慮。

short int;

  • unsigned放在int前,表示變量只能存儲正值。

unsigned int a;


#import <>和""的區(qū)別

雙引號""適用于本地文件,即你自己創(chuàng)建的文件,不是系統(tǒng)文件;尖括號<>導(dǎo)入的是系統(tǒng)文件。使用雙引號時,編譯器一般會首先在項目目錄中尋找指定文件,然后轉(zhuǎn)到其它位置尋找。

  • 理解@property和@synthesize
  • iOS中屬性與成員(實(shí)例)量的區(qū)別
  • 屬性修飾符
  • 深拷貝和淺拷貝
  • 重寫NSString的setter方法

第二部分

  • 理解@property和@synthesize
  • iOS中屬性與成員(實(shí)例)量的區(qū)別
  • 屬性修飾符
  • 深拷貝和淺拷貝
  • 重寫NSString的setter方法

理解@property和@synthesize

@proterty @synthesize詳解

@synthesize 的作用

  • @property,iOS6以后出來的關(guān)鍵字:編譯器會自動給你生成setter(setter方法名即setName)和getter(而getter方法名即name)方法的聲明,以及實(shí)現(xiàn)一個以_name 的成員變量(name是你屬性定義的變量名字)。

  • @synthesize ,簡單來說,就是為屬性聲明實(shí)例變量

    1. @synthesize name = _name;將實(shí)例變量name名稱換成_name。這樣寫是為了區(qū)分成員變量(實(shí)例變量)_name和屬性name,在.m文件里面使用的時候見到_name就知道是成員(實(shí)例)變量了,見到self.name就知道是屬性了。另外,系統(tǒng)庫中的所有類的聲明部分都是這樣寫的, 總之一句話:區(qū)分成員變量名稱和屬性名稱。使用@synthesize可以改變_name名稱
    2. @synthesize name = custom_name:將實(shí)例變量_name名稱換成custom_name
  • @synthesize 還有一個作用,可以指定與屬性對應(yīng)的實(shí)例變量,例如@synthesize myButton = xxx;那么self.myButton其實(shí)是操作的實(shí)例變量xxx,而不是_myButton了。

  • 使用@property,編譯器會自動生成@synthesize name = _name;

  • 如果只寫@synthesize name;那么成員變量的名稱會是name,而不是_name.

  • 注意:@synthesize不會影響@property產(chǎn)生的setter和getter方法的名稱,@property和@synthesize不必成對出現(xiàn)。

  • 禁止@synthesize:如果某屬性已經(jīng)在某處實(shí)現(xiàn)了自己的 setter/getter ,可以使用 @dynamic 來阻止 @synthesize 自動生成新的 setter/getter 覆蓋。

注意:如果你setter和getter兩個方法都重寫了,那么@property是不會自動生成帶有下劃線的成員變量的,需要手動使用synthesize生成。 @synthesize name = _name


iOS中屬性與成員(實(shí)例)量的區(qū)別

iOS中屬性與成員變量的區(qū)別
解惑——iOS中成員變量和屬性區(qū)別

MyViewController.h文件

@interface MyViewController :UIViewController
@property (nonatomic, retain) UIButton *myButton;
@end
  • 在MyViewController.m文件中,編譯器也會自動的生成一個實(shí)例變量_myButton。那么在.m文件中可以直接的使用_myButton實(shí)例變量,也可以通過屬性self.myButton.都是一樣的。注意這里的self.myButton其實(shí)是調(diào)用的myButton屬性的getter/setter方法。
@interface MyViewController :UIViewController
{
    NSString *name;
}
@end
  • .m文件中,self.name 這樣的表達(dá)式是錯誤的。xcode會提示你使用->,改成self->name就可以了。因?yàn)閛c中點(diǎn)表達(dá)式是表示調(diào)用方法,而上面的代碼中沒有name這個方法。
@interface MyViewController :UIViewController
@property (nonatomic, retain) UIButton *myButton;
@end
  • 因?yàn)榫幾g器會自動為你生成以下劃線開頭的實(shí)例變量_myButton,不需要自己手動再去寫實(shí)例變量。而且也不需要在.m文件中寫@synthesize myButton;也會自動為你生成setter,getter方法。@synthesize的作用就是讓編譯器為你自動生成setter與getter方法。

  • @synthesize 還有一個作用,可以指定與屬性對應(yīng)的實(shí)例變量,例如@synthesize myButton = xxx;那么self.myButton其實(shí)是操作的實(shí)例變量xxx,而不是_myButton了。

  • 成員變量用于類內(nèi)部,無需與外界接觸的變量。

  • 根據(jù)成員變量的私有性為了方便訪問,所以就有了屬性變量屬性變量的好處就是允許讓其他對象訪問到該變量。當(dāng)然,你可以設(shè)置只讀或者可寫等,設(shè)置方法也可自定義。所以,屬性變量是用于與其他對象交互的變量。


屬性修飾符

@property后面的關(guān)鍵字

@property 后面可以有哪些修飾符

@property都有哪些修飾詞?以及作用總結(jié)


  • 線程安全的: atomic(原子性), nonatomic(非原子性)
  • 指定方法名稱: setter= getter=
  • 訪問權(quán)限的: readonly(只讀), readwrite (讀寫)
  • 內(nèi)存管理(ARC) assign,strong,weak,copy
  • 內(nèi)存管理(MRC)assign, retain,copy
1. 線程安全(系統(tǒng)默認(rèn)是atomic)
  • nonatomic(英['n?n?'t?m?k]): 禁止多線程,變量保護(hù),提高性能。

    1. 不對set、get方法加同步鎖
    2. 性能好
    3. 線程不安全
  • atomic(英[??t?m?k]): Objc使用的一種線程保護(hù)技術(shù),基本上來講,是防止在寫未完成的時候被另外一個線程讀取,造成數(shù)據(jù)錯誤。而這種機(jī)制是耗費(fèi)系統(tǒng)資源的,所以在iPhone這種小型設(shè)備上,如果沒有使用多線程間的通訊編程,那么nonatomic是一個非常好的選擇。

    1. 原子屬性就是對生成的set方法加互斥鎖(互斥鎖是一種同步鎖,互斥鎖:如果共享數(shù)據(jù)已經(jīng)有其他線程加鎖了,線程會進(jìn)入休眠狀態(tài)等待鎖,一旦被訪問的資源解鎖,則等待訪問資源的線程會被喚醒。自旋鎖:如果共享的數(shù)據(jù)已經(jīng)有其他線程加鎖了,線程會以死循環(huán)的方式等待鎖,一旦被訪問的資源被解鎖,則等待資源的線程會立即執(zhí)行。自旋鎖的效率高于互斥鎖)
    2. 需要消耗系統(tǒng)資源
    3. 互斥鎖是用線程同步實(shí)現(xiàn)的,意在保證同一時間只有一個線程調(diào)用get、set方法。

簡單來講:一般單線程聲明nonatomic,考慮到速度問題。多線程程序就不要使用nonatomic。

OC在定義屬性時有nonatomic和atomic兩種選擇。

atomic:原子屬性,為setter方法加鎖(默認(rèn)就是atomic)。

nonatomic:非原子屬性,不會為setter方法加鎖。

atomic加鎖原理:

 @property (assign, atomic) int age;
 
 - (void)setAge:(int)age
 { 
     @synchronized(self) { 
        _age = age;
     }
 }

互斥鎖

// 注意:鎖定1份代碼只用1把鎖,用多把鎖是無效的
@synchronized(鎖對象) { // 需要鎖定的代碼  }

使用互斥鎖,在同一個時間,只允許一條線程執(zhí)行鎖中的代碼。因?yàn)榛コ怄i的代價非常昂貴,所以鎖定的代碼范圍應(yīng)該盡可能小,只要鎖住資源讀寫部分的代碼即可。使用互斥鎖也會影響并發(fā)的目的。

1. nonatomic和atomic的介紹和區(qū)別

當(dāng)使用atomic時,雖然對屬性的讀和寫是原子性的,但是仍然可能出現(xiàn)線程錯誤:當(dāng)線程A進(jìn)行寫操作,這時其他線程的讀或者寫操作會因?yàn)榈仍摬僮鞫却.?dāng)A線程的寫操作結(jié)束后,B線程進(jìn)行寫操作,所有這些不同線程上的操作都將依次順序執(zhí)行——也就是說,如果一個線程正在執(zhí)行 getter/setter,其他線程就得等待。如果有線程C在A線程讀操作之前release了該屬性,那么還會導(dǎo)致程序崩潰。所以僅僅使用atomic并不會使得線程安全,我們還要為線程添加lock來確保線程的安全。

2. 訪問權(quán)限(默認(rèn)為readwrite)
  • readonly,只生成getter方法,沒有setter方法
  • readwrite,是默認(rèn)的
3. 指定方法名稱: setter= getter=
  • getter=newGetterName,指定新的getter方法名,一般重新改寫B(tài)OOL實(shí)例變量的getter名。例如
@property (getter=isFinished) BOOL finished;  
  • setter=,指定新的setter方法名。
4. **retain(MRC,對象)和strong(ARC,對象)

retain(MRC)

1.release舊對象(舊對象引用計數(shù)-1),retain新對象(新對象引用計數(shù)+1),然后指向新對象

2.在set方法里面是這樣寫的

if(_dog!=nil){
    [_dog release];//先release
}
_dog = [dog retain];//再retain新對象

strong(ARC)(對象)

1.直接賦值,并且對象的引用計數(shù)器加1;

2.在ARC中替代了retain的作用。

相同點(diǎn) :

  • strong 和 retain 都是針對對象類型進(jìn)行內(nèi)存管理。如果去修飾基本數(shù)據(jù)類型,Xcode會直接報錯。
  • 當(dāng)給對象類型使用此修飾符時,setter方法會先將舊的對象屬性release掉,再將新的對象賦值給屬性并對該對象進(jìn)行一次retain操作。
  • 兩者都會增加對象的引用計數(shù)。

不同點(diǎn): strong一般用于ARC環(huán)境, retain用于MRC環(huán)境.

5. assign(ARC/MRC,對象/基本數(shù)據(jù)類型)

1.這個修飾詞是直接賦值的意思,整型、浮點(diǎn)型等基礎(chǔ)數(shù)據(jù)類型都用該修飾詞;

3.assign不會牽扯到內(nèi)存管理,不會增加引用計數(shù)(與weak相同);

2.如果沒有使用weak、strong、retain、copy等詞修飾,默認(rèn)就用assign修飾(它們之間是有你沒我的關(guān)系,一般的指針類型都用strong修飾)

3.當(dāng)然其實(shí)對象也可以用assign修飾,只是對象的計數(shù)器不會加1(與strong的區(qū)別)

4.如果assign用來修飾對象屬性,那么當(dāng)對象被銷毀后指針是不會指向nil的,必須手動將其置為nil,否則會出現(xiàn)野指針錯誤(如果weak指向的對象消失了,那么它會自動置為nil,不會產(chǎn)生野指針;weak只能修飾對象),如果還通過此指針操作那塊內(nèi)存,便會導(dǎo)致EXC_BAD_ACCESS錯誤,調(diào)用了已經(jīng)釋放的內(nèi)存空間。

6. weak(ARC,對象)

1.weak弱指針,修飾對象的修飾詞,也就是說它不能修飾基本數(shù)據(jù)類型(int、float)

2.weak修飾的對象引用計數(shù)器不會加1,也就是直接賦值;(和assign相同,引用計數(shù)都不會增加)

3.弱引用是為打破引用循環(huán)而生的

4.它最被人所喜歡的原因是 它所指向的對象如果被銷毀 , 它會指向nil . 從而不會出現(xiàn)野指針錯誤 。

7. weak和assign的區(qū)別

assign和weak,他們都是弱引用類型,但是他們有區(qū)別的:

1.用weak聲明的變量在棧中會被自動清空,賦值為nil;

2.用assign聲明的變量在棧中可能不會被賦值為nil,就會造成野指針錯誤;

以delegate為例,在MRC中delegate被聲明為assign,這是為了不造成循環(huán)引用,這時我們需要在dealloc中寫上self.delegate = nil;
以免造成delegate的野指針錯誤,當(dāng)然在ARC中只需要用weak聲明delegate就可以自動釋放了。

8. copy(ARC/MRC)

必須要使用copy的情況:(1.屬性是一個不可變對象,如NSString,NSArray,NSDictionry;2.需要把一個可變對象賦值給屬性,如把一個NSMutableString賦值給屬性NSString,除此之外的情況的使用copy和strong是沒區(qū)別的);

1.copy在MRC中時是這樣做的:release舊對象,舊對象引用計數(shù)器減1,copy新對象,新對象的引用計數(shù)器加1,然后指向新對象(新對象是最終指向的那個對象,不管是深拷貝還是淺拷貝)。

在set方法里這樣寫的

- (void)setName:(NSString *)name {
    if(_name){
        [_name release];
    }
    _name = [name copy];
}

2.copy在ARC中是這樣干的,copy新對象,新對象的引用計數(shù)器加1,然后指向新對象。

在set方法里是這樣寫的

- (void)setName:(NSString *)theName {
    if(_name != theName){
       _name = [theName copy];
    }

}

3.使用注意:

  • 修飾的屬性本身必須是不可變的。例如:NSMutableArray采用copy修飾,在addObject時會出現(xiàn)Crash,因?yàn)镹SMutableArray的對象在copy時就會變成NSArray,如需要拷貝NSMutableArray對象用mutableCopy。
  • 遵守NSCopying協(xié)議的對象使用
  1. copy 和 strong 都可修飾不可變類型,但一般用copy
    一般用copy修飾不可變的, 因?yàn)榘踩? 可以保證其封閉性.
    因?yàn)橛胏opy修飾,setter方法中會自動判斷如果來源,如果是不可變的,那和strong一樣,進(jìn)行淺拷貝,會增加其引用計數(shù),如果是可變的那么就深拷貝,不會增加其引用計數(shù)。 所以如果如果項目中這樣的不可變對象(比如NSString)多的話,當(dāng)一定數(shù)量if判斷消耗的時間累加起來就會影響性能.
    所以,只需要記住一點(diǎn),當(dāng)你給你的不可變對象賦值時, 如果來源是可變的,那么就用copy,如果來源是不可變類型的,就用strong。(這句話存疑,因?yàn)槲依斫鉃椋合M桓S源對象變化時才用copy,希望跟隨源對象變化而變化時用strong
    注:如果當(dāng)strong修飾不可變的, 如果來源是不可變得,那么同上,沒有問題。如果來源是可變的時, 那么當(dāng)源對象變化時,我們的不可變屬性也會跟著變化,那么就破壞了其封閉性, 就不安全了。

  2. 如果用 copy 修飾 可變類型 會出現(xiàn)什么問題?
    copy修飾可變的對象的話, 會生成一個不可變的NSCFConstantSting對象,賦值給可變屬性,編譯沒問題,方法修改其內(nèi)容時崩潰:unrecognized selector sent to instance。

總結(jié)

  1. copy 修飾不可變的 要看賦值來源
    • 來源是可變的話, 會自動進(jìn)行深拷貝, 來源對象的變化不會影響我們的不可變屬性
    • 來源是不可變的話,那么就和strong一樣大膽的指針拷貝,反正都不會改變.
  2. copy 修飾可變的.
    • 那么會生成一個不可變對象,賦值給可變屬性,編譯沒問題,調(diào)方法修改其內(nèi)容時會崩潰unrecognized selector sent to instance
  3. strong修飾不可變的 也要看來源
    • 如果來源是不可變的, 那就沒什么問題
    • 如果來源是可變的, 那么當(dāng)源對象的內(nèi)容發(fā)生改變時,我們的不可變屬性的值也會發(fā)生改變,那么就破壞的其封閉性, 不安全.
  4. strong修飾可變的 也要看來源
    • 如果來源是不可變的, 那么會直接報警告運(yùn)行出錯 unrecognized selector sent to instance
    • 如果來源是可變的,那么沒問題.

重寫NSString的setter方法

重寫NSString的setter方法

copy是復(fù)制一個對象,當(dāng)我們不希望新對象隨著舊對象變化而變化時,就要使用copy。
copy修飾的是不可變的對象。

因?yàn)镹SString是一般用copy來修飾。

所以在MRC中,setter方法這樣寫

  • (void)setName:(NSString *)name {
    if(_name){
    [_name release];
    }
    _name = [name copy];
    }

在ARC中,不用release,直接copy。ARC會自動管理內(nèi)存。

  • (void)setName:(NSString *)name {
    _name = [name copy];
    }

注意,不要去加什么判斷比如下面這樣的。
if(_name != name){
_name = [name copy];
}
每次賦值都去判斷一下會更耗時間,這個東西純粹是多余的。


深拷貝和淺拷貝

淺拷貝:指針拷貝
深拷貝:內(nèi)容拷貝(開辟內(nèi)存)

淺拷貝就是對內(nèi)存地址的復(fù)制,讓目標(biāo)對象指針和源對象指向同一片內(nèi)存空間。

深拷貝是指拷貝對象的具體內(nèi)容,而內(nèi)存地址是自主分配的,拷貝結(jié)束之后,兩個對象雖然存的值是相同的,但是內(nèi)存地址不一樣,兩個對象也互不影響,互不干涉。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容