Objective-C是一門面向?qū)ο缶幊?OOP)語言累提,如何編寫一個類斋陪?
Objective-C類基本構(gòu)成
- 由.h頭文件和.m實現(xiàn)文件組成,有如下基本概念:
- 成員變量缔赠、成員屬性嗤堰、成員方法
- 成員方法分類:類方法“+”度宦、對象方法“-”
- 協(xié)議、分類后专、擴展
自定義一個Objective-C類
- 創(chuàng)建一個命令行工程:自定義類.xcodeproj
- 創(chuàng)建一個自定義類:Person類戚哎,一般需要為自定義類添加個人前綴區(qū)分其他人的自定義類建瘫,防止重名沖突尸折。在工程設置選項Class Prefix填入前綴:KNZ实夹,為每次自定義類都添加個人前綴。
- command+N創(chuàng)建一個新的文件,選擇cocoa class准给,按Next
- 創(chuàng)建一個KNZPerson類露氮,并繼承于NSObject钟沛,按Next
- 確保文件添加到targets中恨统,選中勾
- 按Create莫绣,創(chuàng)建好一個KNZPerson類悠鞍,包含兩個文件:KNZPerson.h和KNZPerson.m
為了這個類添加成員變量、成員屬性涧窒、成員方法
- 成員變量:_name纠吴、_age慧瘤、_sex
- 蘋果公司的成員變量命名規(guī)范一般以下劃線“_”開頭锅减,違反規(guī)范會產(chǎn)生各種各樣的問題怔匣。
- 成員方法:類方法+speak,對象方法-talk
- 類方法:向一個類發(fā)送消息;
- 對象方法:先創(chuàng)建一個對象金闽,再向這個對象發(fā)送消息代芜。
在KNZPerson.h中聲明成員變量和成員方法:
<code>
//
// KNZPerson.h
// 自定義類
//
// Created by 李陽 on 2016/10/7.
// Copyright ? 2016年 kenzo. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface KNZPerson : NSObject
{
NSString *_name;
int _age;
BOOL _sex;//YES為男浓利,NO為女
}
+(void)speak;
-(void)talk;
@end
</code>
代碼解析
- #import <Foundation/Foundation.h>:導入Foundation.h頭文件
- “#”->預處理器指令贷掖,編譯前轉(zhuǎn)換為Objective-C代碼
- Foundation羽资,為Objective-C程序提供通用的API基礎
- @interface KNZPerson : NSObject
- “@”->編譯指令屠升,@interface腹暖,這是個接口文件
- KNZPerson : NSObject ->這個KNZPerson類繼承于NSObject類翰萨,NSObject類為所有類的根類,為類提供通用的接口阿蝶。
- {
NSString *_name;
int age;
BOOL sex;//YES為男黄绩,NO為女
}- 成員變量必須寫在{ }里面,不可以向成員變量賦值爽丹。
- 成員方法:+(void)speak;粤蝎、-(void)talk;
- void 無返回值
在KNZPerson.m中實現(xiàn)KNZPerson.h中聲明的所有方法:
<code>
//
// KNZPerson.m
// 自定義類
//
// Created by 李陽 on 2016/10/7.
// Copyright ? 2016年 kenzo. All rights reserved.
//
#import "KNZPerson.h"
@implementation KNZPerson
+(void)speak
{
NSLog(@"你好初澎!speak!");
}
-(void)talk
{
NSLog(@"名字:%@,年齡:%d,男的:%hhd",_name,_age,_sex);
}
@end
</code>
- 所有方法在@implementation KNZPerson...@end內(nèi)部實現(xiàn)
- 類方法+speak無法訪問成員變量碑宴,除非成員變量當參數(shù)傳進來
已經(jīng)實現(xiàn)完基本的Person類,這個類有三個成員變量和兩個成員方法⊙嫘現(xiàn)在想使用這個類匕积。
想使用KNZPerson這個類闪唆,先導入KNZPerson.h頭文件到main.m文件中
<code>
//
// main.m
// 自定義類
//
// Created by 李陽 on 2016/10/7.
// Copyright ? 2016年 kenzo. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "KNZPerson.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
}
return 0;
}
</code>想調(diào)用類方法時钓葫,直接向類發(fā)送類方法消息
- 運行帆调,直接打印“你好番刊!speak影锈!”
想調(diào)用對象方法時,先去創(chuàng)建一個對象熔吗,然后向?qū)ο蟀l(fā)送對象方法消息磁滚。
<code>
//
// main.m
// 自定義類
//
// Created by 李陽 on 2016/10/7.
// Copyright ? 2016年 kenzo. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "KNZPerson.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
KNZPerson *person = [KNZPerson alloc]init;
[person talk];
}
return 0;
}
</code>-
KNZPerson *person = [KNZPerson alloc]init;
- KNZPerson *person:創(chuàng)建一個KNZPerson類型指針變量person垂攘,用來接收返回的對象地址淤刃。
- 一般來說[KNZPerson alloc]init才是真正的創(chuàng)建了一個對象逸贾,而person用來保存這個對象的地址铝侵,但是我們提到對象的話咪鲜,都是指這個保存對象地址的指針。
[person talk]:向這個對象person發(fā)送對象方法消息-talk颖侄。
-
運行览祖,打印
2016-10-07 23:30:28.489370 自定義類[20555:1243524] 名字:(null),年齡:0,男的:0
Program ended with exit code: 0**- 由于初始化時展蒂,沒有給對象的成員變量賦值锰悼,所以都是默認值:基本類型為0悼泌,引用類型為空null馆里。
這次通過在.h頭文件中聲明成員變量的方法自定義一個類鸠踪,這樣設計有個弊端丙者,就是將成員變量都公開了,雖然成員變量作用范圍默認為protected营密,但不符合OOP封裝性械媒。
Snip20161008_20.png
成員變量作用范圍
- @private
- 將成員變量設置為只能在聲明它的類以及該類類型相同的其他實例對象中訪問
- @protected
- 將成員變量設置為只能在聲明它的類及其子類的實例方法中被訪問。成員變量默認范圍评汰。
- @public
- 將成員變量設置為可以被任何代碼訪問
- @package
- 將成員變量設置為可以被其它實例對象或函數(shù)訪問纷捞,但是在其所屬程序包的外部它被視為私有變量,這種作用范圍可以用于庫或者框架類被去。
因此,我們將成員變量在.m文件中聲明惨缆,并提供訪問成員變量的set/get方法,繼續(xù)改進.
- 將成員變量寫在.m文件中糜值,這樣就不會暴露成員變量的信息了
<code>
//
// KNZPerson.m
// 自定義類
//
// Created by 李陽 on 2016/10/7.
// Copyright ? 2016年 kenzo. All rights reserved.
//
#import "KNZPerson.h"
@implementation KNZPerson
{
NSString *_name;
int _age;
BOOL _sex;//YES為男,NO為女
}
+(void)speak
{
NSLog(@"你好坯墨!speak!");
}
-(void)talk
{
NSLog(@"名字:%@,年齡:%d,男的:%d",_name,_age,_sex);
}
@end
</code>
- 接下來在.m文件中重寫init初始化方法寂汇,給對象賦初始值。
[super init]實際是[self init],但是調(diào)用父類的初始化init方法初始化
如果初始化成功捣染,self不為nil骄瓣,執(zhí)行if里面的代碼進行成員變量初始化賦值
最后返回self,這是重寫初始化方法標準格式耍攘,先調(diào)用父類的方法累贤,在判斷是否成功,如果失敗則不執(zhí)行if里面代碼少漆。
運行
2016-10-08 08:04:44.487069 自定義類[24353:1473367] 名字:kenzo,年齡:20,男的:1
Program ended with exit code: 0
- 對象已經(jīng)有初始值了臼膏,然后我再創(chuàng)建一個KNZPerson類的實例對象person2
- 運行
2016-10-08 08:08:29.781012 自定義類[24558:1485252] 名字:kenzo,年齡:20,男的:1
2016-10-08 08:08:29.781207 自定義類[24558:1485252] 名字:kenzo,年齡:20,男的:1
Program ended with exit code: 0
創(chuàng)建的兩個實例對象person、person2都初始化為相同的內(nèi)容了示损,在實際開發(fā)中都是有指定初始化方法的渗磅,無論調(diào)用哪個初始化方法最后都得調(diào)用指定初始化方法,現(xiàn)在自定義指定初始化方法检访。
在KNZPerson.h文件中聲明指定初始化方法
-(instancetype)initWithName:(NSString *)name age:(int)age sex:(BOOL)sex;
在KNZPerson.m文件中實現(xiàn)指定初始化方法
<code>
-(instancetype)initWithName:(NSString *)name age:(int)age sex:(BOOL)sex
{
self = [super init];
if (self) {
_name = name;
_age = age;
_sex = sex;
}
return self;
}
</code>先調(diào)用父類的初始化方法始鱼,初始化成功的話執(zhí)行if里面的代碼,為每個成員變量賦值脆贵。
重新創(chuàng)建person医清、person2對象
<code>
//
// main.m
// 自定義類
//
// Created by 李陽 on 2016/10/7.
// Copyright ? 2016年 kenzo. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "KNZPerson.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
KNZPerson *person = [[KNZPerson alloc]initWithName:@"kenzo" age:28 sex:1];
[person talk];
KNZPerson *person2 = [[KNZPerson alloc]initWithName:@"lucy" age:20 sex:0];
[person2 talk];
}
return 0;
}
</code>一開始創(chuàng)建對象時,就可以給對象成員變量賦值
運行
2016-10-08 08:24:38.128484 自定義類[25391:1536557] 名字:kenzo,年齡:28,男的:1
**2016-10-08 08:24:38.128671 自定義類[25391:1536557] 名字:lucy,年齡:20,男的:0
Program ended with exit code: 0
-
現(xiàn)在我們創(chuàng)建了兩個不同的實例對象卖氨,但是隨著時間推移会烙,對象的年齡會不斷增加负懦,這個時候還要提供訪問成員變量的set/get方法。
- set方法命名規(guī)范:成員變量_age=>setAge
- get方法命名規(guī)范:成員變量_age=>age
-
在KNZPerson.h文件中聲明set/get方法
-(void)setAge:(int)age;- set方法沒有返回值柏腻,參數(shù)類型為成員變量類型
-(int)age;
- get方法返回值類型為成員變量類型
在KNZPerson.m文件中實現(xiàn)set/get方法
<code>
-(void)setAge:(int)age
{
_age = age;
}
-(int)age
{
return _age;
}
</code>這樣纸厉,就可以修改和讀取對象的成員變量的值。
<code>
//
// main.m
// 自定義類
//
// Created by 李陽 on 2016/10/7.
// Copyright ? 2016年 kenzo. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "KNZPerson.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
KNZPerson *person = [[KNZPerson alloc]initWithName:@"kenzo" age:28 sex:1];
[person talk];
KNZPerson *person2 = [[KNZPerson alloc]initWithName:@"lucy" age:20 sex:0];
[person2 talk];</br>
[person setAge:29];
[person2 setAge:21];
NSLog(@"person:%d 歲,person2:%d 歲",[person age],[person2 age]);
}
return 0;
}
</code>先設置person的年齡為29五嫂,person2的年齡為21颗品,然后讀取打印
<code>
2016-10-08 08:39:23.815602 自定義類[26131:1582661] 名字:kenzo,年齡:28,男的:1
2016-10-08 08:39:23.815805 自定義類[26131:1582661] 名字:lucy,年齡:20,男的:0
2016-10-08 08:39:23.815843 自定義類[26131:1582661] person:29 歲,person2:21 歲
Program ended with exit code: 0
</code>
注解
需要為每一個成員變量提供set/get訪問方法,但這些重復性工作沒有多大意義沃缘,蘋果公司推出了自動聲明屬性@property躯枢,它會自動生成成員變量和對應的set/get訪問方法。下一篇:Objective-C總結(jié)----2.如何編寫一個類(下)槐臀,將以自動聲明屬性方式重構(gòu)這個KNZPerson類锄蹂。