你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發綜合 >> iOS開發核心語言Objetive C —— 編譯器指令@property.@synthesize.自定義構造方法及類工廠

iOS開發核心語言Objetive C —— 編譯器指令@property.@synthesize.自定義構造方法及類工廠

編輯:IOS開發綜合

本分享是面向有意向從事iOS開發的伙伴們,或者已經從事了iOS的開發者。如果您對iOS開發有極高的興趣,可以與我一起探討iOS開發,一起學習,共同進步。如果您是零基礎,建議您先翻閱我之前分享的iOS開發分分鐘搞定C語言系列,然後在開始Objective C語言的學習,如果您遇到問題也可以與我探討,另外將無償分享自己整理的大概400G iOS學習視頻及學習資料,都是干貨哦!可以新浪微博私信?關注極客James,期待與您的共同學習和探討!!由於時間有限,每天在工作之余整理的學習分享,難免有不足之處,也希望各路大神指正!

made by :極客James
這裡寫圖片描述

一、@prZ喎?/kf/ware/vc/" target="_blank" class="keylink">vcGVydHmx4NLrxvfWuMHuPC9zdHJvbmc+PGJyIC8+DQo8c3Ryb25nPjEuQHByb3BlcnR5uMXE7jwvc3Ryb25nPjxiciAvPg0Ko6gxo6nK18/IQHByb3BlcnR5ysex4NLrxve1xNa4we48YnIgLz4NCqOoMqOpseDS68b31rjB7r7NysfTw8C0uObL37Hg0uvG99Kq1/bKssO0o6zOqsHLvdrKodbYuLS0+sLrvLDM4bmps8zQ8tSxseDC6zxiciAvPg0Ko6gzo6lAcHJvcGVydHkg08PU2sn5w/fOxLz+1tC45svfseDS68b3yfnD97PJ1LGx5MG/tcS1xLfDzsrG9yhnZXR0ZXIvc2V0dGVyKbe9t6g8YnIgLz4NCqOoNKOp1eLR+bXEusO0psrHOsPiyKXO0sPHyta5pMrp0LRnZXR0ZXK6zXNldHRlcre9t6i3scv2tcS0+sLrPC9wPg0KPHA+PHN0cm9uZz4yLkBwcm9wZXJ0ecq508M8L3N0cm9uZz48YnIgLz4NCqOoMaOp1NpAaW50ZWZhY2XW0KOs08PAtNfUtq/J+rPJc2V0dGVyus1nZXR0ZXK1xMn5w/ehozxiciAvPg0K08NAcHJvcGVydHkgaW50IGFnZTu+zb/J0tS0+szmz8LD5rXEwb3Q0DwvcD4NCjxwcmUgY2xhc3M9"brush:java;"> - (int)age; // getter - (void)setAge:(int)age; // setter

3.@property編寫步驟
(1)在@inteface和@end之間寫上@property
(2)在@property後面寫上需要生成getter/setter方法聲明的屬性名稱, 注意因為getter/setter方法名稱中得屬性不需要, 所以@property後的屬性也不需要.並且@property和屬性名稱之間要用空格隔開
(3)在@property和屬性名字之間告訴需要生成的屬性的數據類型, 注意兩邊都需要加上空格隔開。

4.@property增強特性
自從Xcode 4.x後,@property可以同時生成setter和getter的聲明和實現方法。

(1)默認情況下,setter和getter方法中的實現,會去訪問下劃線 _ 開頭的成員變量。

@interface Person : NSObject
{
    @public
    int _age;
    int age;
}
@property int age;

@end

int main(int argc, const char * argv[]) {

    Person *p = [Person new];
    [p setAge:30];
    NSLog(@age = %i, _age = %i, p->age, p->_age);

    return 0;
}

(2)如果沒有會自動生成一個_開頭的成員變量,自動生成的成員變量是私有變量, 聲明在.m中,在其它文件中無法查看,但當可以在本類中查看
@property只會生成最簡單的getter/setter方法,而不會進行數據判斷

Person *p = [Person new];
[p setAge:-10];
NSLog(@age = %i, [p age]);

(3)如果需要對數據進行判斷需要我們之間重寫getter/setter方法
(4)若手動實現了setter方法,編譯器就只會自動生成getter方法
(5)若手動實現了getter方法,編譯器就只會自動生成setter方法
(6)若同時手動實現了setter和getter方法,編譯器就不會自動生成不存在的成員變量

5.@property修飾符
readonly 只生成setter方法,不生成getter方法
readwrite 既生成getter 又生成setter方法(默認)
@property (readonly) int age;
指定所生成的方法的方法名稱
getter=你定制的getter方法名稱
setter=你定義的setter方法名稱(注意setter方法必須要有 :)
如果給一個屬性同時提供了getter/setter方法, 那麼我們稱這個屬性為可讀可寫屬性
如果只提供了getter方法, 那麼我們稱這個屬性為只讀屬性
如果只提供了setter方法, 那麼我們稱這個屬性為只寫屬性
如果既沒有提供getter也沒有提供setter方法, 那麼我們稱這個屬性為私有屬性

格式:
@property(屬性修飾符) 數據類型 變量名稱;
readwrite: 代表既生成getter方法 , 也生成setter方法

三、@synthesize
1.@synthesize的概念
(1)@synthesize是編譯器的指令
(2)編譯器指令就是用來告訴編譯器要做什麼!
(3)@synthesize 用在實現文件中告訴編譯器實現成員變量的的訪問器(getter/setter)方法
(4)好處是:免去我們手工書寫getterr和setter方法繁瑣的代碼

2.@synthesize基本使用
用@synthesize age = _age;就可以代替

- (int)age{
    return _age;
}
- (void)setAge:(int)age{
    _age = age;
}

3.@synthesize編寫步驟
(1)在@implementation和@end之間寫上@synthesize
(2)在@synthesize後面寫上和@property中一樣的屬性名稱, 這樣@synthesize就會將@property生成的什麼拷貝到@implementation中
(3)由於getter/setter方法實現是要將傳入的形參給屬性和獲取屬性的值,所以在@synthesize的屬性後面寫上要將傳入的值賦值給誰和要返回哪個屬性的值, 並用等號連接。

4.@synthesize注意點
(1)@synthesize age = _age;
setter和getter實現中會訪問成員變量_age
如果成員變量_age不存在,就會自動生成一個@private的成員變量_age
@synthesize age;

(2)setter和getter實現中會訪問@synthesize後同名成員變量age
如果成員變量age不存在,就會自動生成一個@private的成員變量age
多個屬性可以通過一行@synthesize搞定,多個屬性之間用逗號連接。

三、靜態類型和動態類型
1.靜態類型和動態類型的定義
(1)靜態類型,將一個指針變量定義為特定類的對象時,使用的是靜態類型,在編譯的時候就知道這個指針變量所屬的類,這個變量總是存儲特定類的對象。
(2)動態類型,這一特性是程序直到執行時才確定對象所屬的類

2.id數據類型
(1)id是一個數據類型, 並且是一個動態數據類型
既然是數據類型, 所以就可以用來:
- 定義變量
- 作為函數的參數
- 作為函數的返回值
默認情況下所有的數據類型都是靜態數據類型

3.靜態數據類型的特點
(1)在編譯時就知道變量的類型,
(2)知道變量中有哪些屬性和方法
(3)在編譯的時候就可以訪問這些屬性和方法, 並且如果是通過靜態數據類型定義變量, 如果訪問了不屬於靜態數據類型的屬性和方法, 那麼編譯器就會報錯

4.動態數據類型的特點:
在編譯的時候編譯器並不知道變量的真實類型, 只有在運行的時候才知道它的真實類型。
並且如果通過動態數據類型定義變量, 如果訪問了不屬於動態數據類型的屬性和方法, 編譯器不會報錯

 id == NSObject * 萬能指針
 id和NSObject *的區別: 
 NSObject *是一個靜態數據類型

通過靜態數據類型定義變量, 不能調用子類特有的方法
通過動態數據類型定義變量, 可以調用子類特有的方法
通過動態數據類型定義的變量, 可以調用私有方法

弊端: 由於動態數據類型可以調用任意方法, 所以有可能調用到不屬於自己的方法, 而編譯時又不會報錯, 所以可能導致運行時的錯誤
應用場景: 多態,可以減少代碼量, 避免調用子類特有的方法需要強制類型轉換。

5.instancetype
(1) instancetype == id == 萬能指針 == 指向一個對象
(2)id在編譯的時候不能判斷對象的真實類型
(3)instancetype在編譯的時候可以判斷對象的真實類型
(4) id和instancetype除了一個在編譯時不知道真實類型, 一個在編譯時知道真實類型以外, 還有一個區別
(5)id可以用來定義變量, 可以作為返回值, 可以作為形參
(6)instancetype只能用於作為返回值

注意: 以後用到自定義構造方法, 返回值盡量使用instancetype, 不要使用id

四、構造方法
1.init方法
想在對象創建完畢後,成員變量馬上就有一些默認的值就可以重寫init方法。
重寫init方法格式:

- (instancetype)init {
    self = [super init];
    if (self) {
        // Initialize self.
    }
    return self;
}

2.構造方法使用注意
(1)子類擁有的成員變量包括自己的成員變量以及從父類繼承而來的成員變量,在重寫構造方法的時候應該首先對從父類繼承而來的成員變量先進行初始化。
原則:先初始化父類的,再初始化子類的。
先調用父類的構造方法[super init];
再進行子類內部成員變量的初始化。
千萬不要把self = [super init]寫成self == [super init]
重寫構造方法的目的:為了讓對象方法一創建出來,成員變量就會有一些固定的值。

3.自定義構造方法
有時候僅僅靠重寫構造方法(初始化方法),不能滿足需求。比如一個班級中不可能所有學生的年齡都一樣,這時候我們需要在創建某個學生的時候能夠傳入這個學生的年齡。這時候就需要來自定義構造函數(初始化函數)

4.自定義構造方法的規范
(1)一定是對象方法,以減號開頭
(2)返回值一般是instancetype類型
(3)方法名必須以initWith開頭

實例:

.h 聲明文件
@interface Person : NSObject
@property int age;
@property NSString *name;
// 當想讓對象一創建就擁有一些指定的值,就可以使用自定義構造方法
- (id)initWithAge:(int)age;
- (id)initWithName:(NSString *)name;
- (id)initWithAge:(int)age andName:(NSString *)name;
@end

.m 實現文件
- (id)initWithAge:(int)age{
if(self = [super init]){
    _age = age;
}
return self;
}

- (id)initWithName:(NSString *)name{
if (self = [super init]){
_name = name ;
}
return self;
}

- (id)initWithAge:(int)age andName:(NSString *)name{
if(self = [super init]){
    _name = name;

}
return self;
}

5.自定義方法的繼承
(1)不能在子類訪問父類私有變量.
(2)父類的屬性交給父類的方法來處理
(3)自定義構造方法必須以intiWith開頭,並且’W’必須大寫

6.自定義類工廠方法
什麼是類工廠方法:
用於快速創建對象的類方法, 我們稱之為類工廠方法
類工廠方法中主要用於 給對象分配存儲空間和初始化這塊存儲空間

規范:
1.一定是類方法 +
2.方法名稱以類的名稱開頭, 首字母小寫
3.一定有返回值, 返回值是id/instancetype

實例:

.h 文件聲明
@interface Person : NSObject
@property  int  age;

+ (instancetype)person;

+ (instancetype)personWithAge:(int)age;

@end
.m文件實現
+(instancetype)person{

return   [[Person alloc]init];
}

+ (instancetype)personWithAge:(int)age{
Person *p = [[Person alloc]init];
p.age = age;
return p;
}

7.類方法工廠方法的繼承
注意:
(1) 但凡自定義類工廠方法, 在類工廠方法中創建對象一定不要使用類名來創建。
(2)一定要使用self來創建
(3)self在類方法中就代表類對象, 到底代表哪一個類對象呢?,誰調用當前方法, self就代表誰。
實例代碼:

.h文件
@property int age;
+(instancetype)person;
+(instancetype)personWithAge:(int)age;

.m文件
+(instancetype)person{
return    [[self alloc]init];
}
+(instancetype)personWithAge:(int)age{
person *p = [[self alloc]init];
p.age = age;
return = p;
}

五、類的本質及啟動過程
(1)類的本質其實也是一個對象(類對象)
(2)程序中第一次使用該類的時候被創建,在整個程序中只有一份。
(3)此後每次使用都是這個類對象,它在程序運行時一直存在。
(4)類對象是一種數據結構,存儲類的基本信息:類大小,類名稱,類的版本,繼承層次,以及消息與函數的映射表等
(5)類對象代表類,Class類型,對象方法屬於類對象
(6)如果消息的接收者是類名,則類名代表類對象
(7)所有類的實例都由類對象生成,類對象會把實例的isa的值修改成自己的地址,每個實例的isa都指向該實例的類對象

六、OC實例對象 類對象 元對象之間關系
(1)每一個對象 都是一個類的實例。
(2)每一個對象 都有一個名為isa的指針,指向該對象的類。
(3)每一個類描述了一系列它的實例的特點,包括成員變量的列表,成員函數的列表等。
(4)每一個對象都可以接受消息,而對象能夠接收的消息列表是保存在它所對應的類中。

這裡寫圖片描述

 

  1. 上一頁:
  2. 下一頁:
Copyright © Ios教程網 All Rights Reserved