讓代碼書寫更加簡便 【寫在開頭】 『在面向對象的編程中,封裝是其一個重要的特性。封裝將一個可供外部使用的介面暴露出來,隱藏了複雜的代碼邏輯實現。 外部就可以通過設置器setter和訪問器getter來對對象的屬性進行設置和訪問,而不是直接訪問對象的屬性-> --1-- 設置器和訪問器 1.1 set ...
讓代碼書寫更加簡便
--1-- 設置器和訪問器1.1 setter1.2 getter--2-- 類的本質2.1 類類型的對象2.2 類的本質2.3 如何獲取類對象2.4 類對象的使用2.5 類對象的存儲--3-- SEL類型3.1 SEL--4-- @property關鍵字4.1 基本概念4.2 @property用法4.3 @property使用註意事項--5-- @synthesize關鍵字5.1 @synthesize用法5.2 @synthesize使用註意5.3 @synthesize指定實例變數賦值--6-- self關鍵字6.1 介紹6.2 在對象方法中使用self6.3 用在類方法中使用self-------------------------------------
【寫在開頭】
『在面向對象的編程中,封裝是其一個重要的特性。封裝將一個可供外部使用的介面暴露出來,隱藏了複雜的代碼邏輯實現。
不可被外部任意存儲是面向對象設計的本質,降低了數據被無用的可能性。
外部就可以通過設置器setter和訪問器getter來對對象的屬性進行設置和訪問,而不是直接訪問對象的屬性(->)
在開發過程中,考慮到安全性要求,一般不再成員變數名前面使用@public、@protected等關鍵字修飾,而是使用Set方法來為對象提供成員變數的值,在set方法的內部也可以對一些不合理的賦值進行篩選過濾。』
--1-- 設置器和訪問器
1.1 setter
setter方法(設置器):在set方法的內部可以對一些不合理的數據過濾篩選。set方法作用:為提供一個設置成員變數值的方法。
命名規範:
1)方法名必須以set開頭
2)set後面跟上成員變數的名稱,首字母大寫
3)返回值一定是void
4)一定要接受一個參數,而且參數類型需要和成員變數的類型一致
5)形參名不能和變數名一樣(成員變數名以_線開頭,蘋果官方推薦成員變數名前加_以示區分)
好處:
1)不讓數據暴露在外,保證了數據的安全性
2)對設置的數據進行過濾
{ //成員屬性 NSString *_name; int _age; }
setter
//setter - (void)setName:(NSString *)name; - (void)setAage:(int)age;
1.2 getter
作用:為調用者返回對象內部的成員變數
命名規範:
1)一定有返回值,返回值的類型和成員變數的類型一致
2)方法名和去掉下劃線的成員變數名一樣(此處與Java等語言不一樣)
3)不需要接收任何參數
//getter - (NSString *)name; - (int)age;
--2-- 類的本質
2.1 類類型的對象
類的本質其實也是對象,只不過是class類型的對象,也叫做類對象
2.2 類對象
類對象
* 類對象在程式運行時一直存在
* 類對象是一種數據結構,存儲類的基本信息:類大小,類名,類的版本以及消息與函數的映射表等
* 類對象所保存的信息是在程式編譯時確定,在第一次使用該類的時候被載入到記憶體中
* 類對象代表類,class代表類對象,類方法屬於類對象
* 如果消息的接收者是類名,則類名代表類對象
* 運行時,所有類的實例都由類對象生成,類對象會把實例的isa的值修改成自己的地址,每個實例的isa都指向該實例的類對象
* 從類對象里可以知道父類的信息、可以響應的方法等
* 類對象只能使用類方法,不能使用實例方法
2.3 如何獲取類對象
1)通過實例對象獲取
Person *person = [[Person alloc] init]; //創建對象 //通過實例對象獲取類對象Dog Class c1 = [person class]; //Class類型的是一個結構體指針 Class c2 = [person class]; NSLog(@"c1->%p", c1); //0x1000011d8 NSLog(@"c2->%p", c2); //0x1000011d8
2)通過類名獲取(類名其實就是類對象)
//通過類名獲取類對象 Class c3 = [Person class]; NSLog(@"c3->%p", c3); //0x1000011d8
發現通過類名和實例獲取對象,所獲得的對象是同一個
實際上,都是獲得了類對象Person class
2.4 類對象的使用
1)用類對象創建對象
兩個測試方法:
//對象方法 - (void)test; //類方法 + (void)test;
使用
//用類對象來創建對象 Person *person2 = [[c1 alloc] init]; [person2 test]; //調用對象方法的test -test
2)用類對象來調用類方法
//用類對象來調用類方法 [c1 test]; //調用類方法 +test
2.5 類對象的存儲
isa指針
- 每一個對象都包含一個isa指針.這個指針指向當前對象所屬的類。
- [p eat];表示給p所指向的對象發送一條eat消息,調用對象的eat方法,此時對象會順著內部的isa指針找到存 儲於類中的方法,執行。
- isa是對象中的隱藏指針,指向創建這個對象的類。
- 通過isa指針我們可以在運行的時候知道當前對象是屬於那個Class(類)的。
--3-- SEL類型
3.1 SEL
SEL:全稱selector,表示方法的存儲位置
方法調用的原理:其實每個類載入到記憶體中對象的方法都會封裝成一系列的SEL列表,SEL會保存著這個方法的信息(當然包括方法的記憶體地址),當要調用該方法的時候,對象會通過isa指針找到記憶體中對應的方法的記憶體地址然後再調用該方法,在找到該方法之後該類對象會把該SEL放入緩存中,以便第二次尋找的時候提高效率
Person *p = [[Person alloc] init];
[p test];
尋找方法的過程
1)首先把test這個方法名包裝成SEL類型的數據
2)根據SEL數據找到對應的方法地址
3)根據方法地址調用相應的方法
4)註意:在這個操作過程中有緩存,第一次找的時候是一個一個的找,非常耗性能,之後再用到的時候就直接使用了
--4-- @property關鍵字
4.1 基本概念
@property是編譯器的指令。(編譯器指令是由編譯器完成的)
好處是免去我們手工書寫成員屬性getter和setter方法繁瑣的代碼。
4.2 @property用法
格式:
@property 類型名 方法名
如:
@property int age;
相當於完成了age屬性的set和get方法的聲明和實現
- (void)setAge:(int)age;
- (void)age;
註意:
1、在Xcode4.4之前,用於幫我們實現get/set方法的聲明
2、在Xcode4.4之後,有增強功能,連實現也自動完成了
Person.h->
/* 省略了方法的聲明 相當於是替換了下麵的這兩句聲明 - (void)setAge:(int)age; - (int)age; 同時,還自動生成了對應的成員屬性 _age,但是這個屬性是私有的,外部只能通過setter/getter訪問 */ @property int age;
Person類中沒有自定義 _age屬性,但是@property自動生成了該屬性:
@implementation Person //對象方法 - (void)test{ NSLog(@"-TEST"); self->_age = 3; //在這裡可以看到,@property生成了一個_age屬性 } //類方法 + (void)test{ NSLog(@"+TEST"); } @end
調用:
Person *person = [[Person alloc] init]; //創建對象 //此處 _age屬性由@property生成 person.age = 3; //設置成員屬性 NSLog(@"person.age->%d", person.age); //3
4.3 @property使用註意事項
在老式的代碼中
@property只能寫在@interface ...@end之間
@property用來自動生成成員變數get/set方法的聲明(Xcode4.4之前)
告訴@property要生成的get/set方法聲明的成員變數類型是聲明
告訴@property要生成的get/set方法是哪個屬性的,屬性名去掉下劃線
--5-- @synthesize關鍵字
5.1 @synthesize用法
@synthesize age;
寫在.m文件中,表示對生成.h中變數age的get和set方法的實現
格式:
@synthesize 方法名
註意:
如果使用@synthesize則變數名要先在.h文件中聲明
.h
@property int age;
.m
@synthesize age;
展開形式如下:
@synthesize age; //展開 - (void)setAge:(int)age{ self->age = age; //註意這裡不是對Person原來的成員變數_age賦值,而是生成了一個變數age,然後對其進行賦值 //(如果這裡寫self,那麼這個變數age也就相當於是個成員變數了) //所以使用@synthesize時,下麵只列印了age和name的值,沒有對_age和_name進行操作 //NSLog(@"age = %d, name = %@", age, name); //NSLog(@"_age = %d, _name = %@", _age, _name); }
5.2 @synthesize使用註意
Xcode4.4之前@property和@synthesize搭配使用,用於簡化set和get方法的定義和實現
5.3 @synthesize指定實例變數賦值
聲明
@property int a;
實現
@sythesize a = _b; //表示用a的get和set方法,修改屬性b的值
相當於下麵的代碼:
- (void) setA:(int)a{
_b = a;
}
- (int)a{
reurn _b;
}
@interface Person : NSObject @property NSString *name; //如果兩個實例變數的類型一致,如:age和weight,@property可以用逗號隔開變數,在一行上定義 @property int age, weight; //測試方法 - (void)test; @end @implementation Person //用age的getter和setter方法,修改屬性_age的值 @synthesize age = _age, name = _name, weight = _weight; @end
--6-- self關鍵字
6.1 介紹
OC語言中的self,就相當於C++、Java中的this指針。
學會使用self,首先要搞清楚屬性這一概念。
以及理解getter(訪問器)和setter(設置器)方法,它到底有什麼用?
設置器與訪問器,提供外界操作 類內部屬性的一個通道。
假如沒有這個方法,外界怎麼操作類的內部屬性。
假如不提供這兩個方法,那麼這個屬性的值,就不能為外界所改變。
因為類的屬性,預設是@protect(受保護類型)。
self的應用場景
1)用在類方法中
2)用在對象方法中
3)訪問成員變數
4)self在OC的記憶體管理特殊使用
6.2 在對象方法中使用self
//學生學習對象方法 - (void)study{ //此時self指代學生對象 NSLog(@"- self->%p", self); //0x1002001b0 }
6.3 用在類方法中使用self
//學生信息類方法 + (void)info{ //此時self指代學生類 NSLog(@"+ self->%p", self); //0x1000013d0 }
查看:
@autoreleasepool { Student *stu = [[Student alloc] init]; //學生對象地址 NSLog(@"stu->%p", stu); //0x1002001b0 //學生類地址 NSLog(@"Student-%p", [Student class]); //0x1000013d0 //發送study和info消息 [Student info]; //0x1000013d0 [stu study]; //0x1002001b0 }
輸出-->
綜上總結:
self要指代誰?具體是要看self寫在哪個方法中,
如果self寫在對象方法中,則指代的就是當前方法的對象([類 new])
如果self寫在類方法中,那麼它指代的就是當前的類對象(類 class)
註意這裡類對象和對象是兩個概念
【寫在結尾:】
『想起一首席慕容的詩:
一棵開花的樹 如何讓你遇見我 在我最美麗的時刻 為這 我已在佛前求了五百年 求佛讓我們結一段塵緣 佛於是把我化做一棵樹 長在你必經的路旁 陽光下 慎重地開滿了花 朵朵都是我前世的盼望 當你走近 請你細聽 那顫抖的葉 是我等待的熱情 而當你終於無視地走過 在你身後落了一地的 朋友啊 那不是花瓣 那是我凋零的心』