http://my.oschina.net/luoguankun/blog/219532
一、成員變量的作用域
· @public
· 在任何地方都能直接訪問對象的成員變量
· @private
· 只能在當前類的對象方法中訪問
· @protected(可以不寫,默認)
· 能在當前類和子類的對象方法中直接訪問
· @package
· 只要處在同一個框架中,就能直接訪問對象的成員變量
· @interface和@implementation中不能聲明同名的成員變量
· 在@implementation中聲明變量,默認是@private的
二、點語法
· 點語法的本質還是方法調用,不是調用成員變量
· 編譯器遇到點語法時,會把點語法轉成方法
?
1
2
3
p.age = 10; //[p setAge:10];
intage = p.age; //[p age];
三、構造方法
· 用來初始化對象的方法,對象方法,以減號開頭
· 為了讓對象創建出來,成員變量就會有一些固定的值
· 重寫構造方法的注意點:
· 先調用父類的構造方法([super init])
· 再進行子類內部成員變量的初始化
· + alloc 方法
· 分配存儲空間
· - init 方法
· 初始化
· 實際上是這么創建對象的
?
1
Person *p5 = [[Person alloc] init]; //先分配存儲空間,再進行初始化
· 重寫NSObject類的init方法(無參數)
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- (id)init
{
//一定要調用回super得init方法:初始化父類中聲明的一些成員變量和其他屬性
if(self = [super init]) {
//初始化成功
_age = 10;
}
returnself;
}
· 帶參數的構造方法
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- (id)initWithName:(NSString *)name andAge:(int)age
{
if(self = [super init]) {
_age = age;
_name = name;
}
returnself;
}
四、分類
· 分類,在不改變原來模型的情況下,可以給某個類擴充一些方法
· 分類只能增加方法,不能增加成員變量
· 分類方法實現中可以訪問原來類中聲明的成員變量
· 分類的優先級最高,方法優先去分類中去找,再去原來類中去找,最后再去父類中找
· 分類可以重寫原來類中的方法,但是會覆蓋掉,會導致原來的方法失效,沒法再使用
· 方法調用的優先級:分類(最后參與編譯的分類優先) --> 原來類 --> 父類
· 分類的應用一般是擴展系統的類的方法,比如擴展NSString類的方法
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
- (int)numberCountOfString:(NSString *)str
{
intcount = 0;
for(unsigned longi = 0; i < [str length]; i++) {
unichar ch = [str characterAtIndex:i];
if(ch >= '0'&& ch <='9') {
count++;
}
}
returncount;
//return [str numberCount];
}
//計算某個字符串中阿拉伯數字的個數(對象方法)
- (int)numberCount
{
intcount = 0;
for(unsigned i = 0 ; i < [self length]; i++) {
unichar ch = [self characterAtIndex:i];
if(ch >= '0'&& ch <='9') {
count++;
}
}
returncount;
//return [NSString numberCountOfString:self];
}
五、類的本質
· 可以使用類創建對象,但是類本身也是一個對象,是個Class類型的對象,簡稱“類對象
· 先利用Class創建一個Person類對象,再利用Person類對象,創建Person類型的對象
· 重寫load()方法和initialize()方法
?
1
2
3
4
5
6
7
8
9
10
11
- (void)load
{
NSLog(@"Student的load方法被調用");
}
//在第一次被使用的時候就會被調用一次,監聽類第一次被使用的時候
- (void)initialize
{
NSLog(@"Student-initialize方法被調用");
}
· load()方法:
· 當程序啟動時,就會加載項目中所有的類和分類,而且加載后會調用每個類和分類的load方法。只會調用一次
· 當第一次使用某個類時,就會調用當前類的+initialize方法
· 先加載父類,再加載子類(先調用父類的load方法,再調用子類的load方法)
· 先初始化父類,再初始化子類(先調用父類的initialize方法,再調用子類的initialize方法
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//利用Person這個類創建了3個Person類型的對象
Person *p = [[Person alloc] init];
Person *p2 = [[Person alloc] init];
Person *p3 = [[Person alloc] init];
//先利用Class創建一個Person類對象
//再利用Person類對象,創建Person類型的對象
//獲取內存中的類對象
Class c = [p class];
Class c2 = [p class];
//獲取內存中的類對象
Class c3 = [Person class];
NSLog(@"c=%p,c2=%p,c3=%p",c,c2,c3); //c的地址等于c2,也等于c3
//程序先加載父類,再加載子類,而且類只被加載一次
//只要加載了類,就會調用load類方法
//initialize類方法是在類第一次被初始化時,被調用,如果在使用子類的時候,父類也會被調用該方法
//分類也會被加載,如果原始類和分類都重寫了initialize方法,那么分類的initialize方法優先被調用,原始類不調用
GoodStudent *stu = [[GoodStudent alloc] init];
六、自動生成getter和setter方法
· @property自動生成某個成員變量的聲明
· @synthesize自動生成getter和setter的實現,并且會訪問指定的成員變量
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//自動生成某個成員變量的聲明
//編譯器特性:編譯器當遇到@property時,自動轉換成setter和getter聲明方法
// - (void)setAge:(int)age;
// - (int)age;
@propertyintage; //生成_age成員變量
@propertydoubleheight; //生成_height成員變量
@propertydoubleweight; //生成_weight成員變量
@property NSString *name; //生成_name成員變量
//@synthesize自動生成getter和setter的實現,并且會訪問指定的成員變量
@synthesize age = _age;
@synthesize height = _height;
//用逗號分隔
@synthesize weight = _weight,name = _name;
· @synthesize可以不寫,只寫@property就可以完成成員變量getter和setter方法的聲明和實現
七、description方法
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
import <Foundation/Foundation.h>
import "Person.h"
intmain()
{
//輸出行號
NSLog(@"%d",LINE);
//NSLog輸出C語言字符串的時候,不能有中文
NSLog(@"%s",__FILE__);
//輸出源文件路徑名稱
printf("%s\n",__FILE__);
//輸出當前函數名
NSLog(@"%s",__func__);
return0;
}
voidtest()
{
Person *p = [[Person alloc] init];
p.age = 20;
p.name = @"Jack";
//1.首先會調用對象的-description方法,返回字符串
//2.拿到-description方法的返回值,并顯示到屏幕上
//description方法默認返回“類名+內存地址” <Person 0x0232010>
//所以需要重寫description方法
//相當于java的Object的toString()方法
NSLog(@"%@",p.description);
Person *p2 = [[Person alloc] init];
p2.age = 22;
p2.name = @"Ted";
NSLog(@"%@",p2.description);
}
voidtest2()
{
Class c = [Person class];
//1.首先會調用類的+description方法
//2.拿到+description方法的返回值(NSString *)顯示到屏幕上
NSLog(@"%@",c);
}
//重寫description方法
-
(NSString *)description
{
//死循環
//NSLog(@"%@",self);return[NSString stringWithFormat:@"age=%d,name=%@",_age,_name];
}
- (NSString *)description
{
return@"sss";
}
八、id類型
· id是一種類型
· id是萬能指針,能操作任何OC對象,id內部已經包含,所以不用再加
· 示例:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
intmain()
{
//id是一種類型
//id是萬能指針,能操作任何OC對象,id內部已經包含,所以不用再加
//id d;
//Person *p = [Person new];
//id == NSObject*
//NSObject *o = [Person new];
//只適用OC對象
id person = [Person new];
[person setAge:10];
[person setObj:@"luoguankun"];
NSLog(@"age=%d",[person age]);
test(person);
return0;
}
九、SEL
· SEL其實是對方法的一種包裝,將方法包裝成一個SEL類型的數據,去找對應的方法地址,找到方法地址就可以調用方法
· 其實消息就是SEL
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
intmain()
{
//[Person test];
Person *p = [[Person alloc] init];
//1.把test2包裝成SEL類型的數據
//2.根據SEL數據找到對應的方法地址
//3.根據方法地址調用對應的方法
//[p test2];
//通過SEL簡介調用test方法
[p performSelector:@selector(test2)];
//上面的調用相當于下面這兩步
//SEL s = @selector(test2);
//[p performSelector:s];
//通過SEL帶參數的形式調用test3方法,不要忘了帶上冒號
[p performSelector:@selector(test3:andluo:) withObject:@"luo"withObject:@"feng"];
return0;
}
//字符串轉換成SEL
NSString *name = @"test2";
SEL s = NSSelectorFromString(name);
//SEL轉換成字符串
-
(void)test2
{
//死循環
//[self performSelector:_cmd];//_cmd是SEL類型,代表當前方法
//通過NSString的fromSelector方法把SEL轉換為字符串
NSString *str = NSStringFromSelector(_cmd);//打印_cmd
NSLog(@"%@",str); //打印test2
}