OC05核心語法總結 2


六、 分類

知識點

主題1:分類category依賴於類,新建時,創建category模板

1.不改變原來類模型的基礎上來擴充方法
2.格式:
@interface 類名(分類名稱)
 -
@end

@implementation 類名(分類名稱)
@end
3.調用:首先把相應的頭文件包含進來
[p study];//和以前調用方式一模樣
4.如果(龐大的)類方法很多(模塊)時,要好多人去寫,這時就可以按人去分類,然後調用的時候該咋調用咋調用
5.總結:
    1)不改變原來類內容的基礎上爲類增加一些方法。
    2)只能增加方法,不能增加成員變量
    3)分類的實現是可以訪問原來類裏的成員變量
    4)如果擴充的方法名和原來的方法名一樣時(重寫),會覆蓋原來的方法。
因爲分類的方法的調用優先級高於原來的類方法,就是先去分類中找,然後再去原來的類去找,最後去父類
    5)那如果多個擴充文件裏也存在的一樣的呢?測試下,結果:是調用最後編譯的分類方法。
    (因爲相同名字方法編譯一次覆蓋一次,只保留最後一個)

主題2:給NSString 類添加類方法

1.系統自帶的類,有時不能滿足自己的需要:比如:要求求出字符串中含有的阿拉伯數字的個數
2.步驟:
    1*選在分類category模板 在NSString上分
    2*擴充一個類方法 +開頭
3.聲明和實現文件
//.h
#import <Foundation/Foundation.h>

@interface NSString (Number)

+ (int)numberCountOfString:(NSString *)str;

- (int)numberCount;

@end
//.m
#import "NSString+Number.h"

@implementation NSString (Number)
+ (int)numberCountOfString:(NSString *)str
{
    int count=0;//局部變量要進行初始化,不然後果很嚴重
    for (int i=0;i<[str length];i++
    {
        unichar c=[str characterAtIndex:i];//獲取這個字符串的第i個字符
        if ( c>=‘0’&&c<=‘9’)
              {
            count++;
        }
    }
    return count;
}
@end

主題3:給NSString 類添加對象方法

#import "NSString+Number.h"

@implementation NSString (Number)
- (int)numberCount
{
int count=0;//局部變量要進行初始化,不然後果很嚴重
    for (int i=0;i<[self length];i++//當前字符串對象的
    {
        unichar c=[self characterAtIndex:i];//獲取第一個字符
        if ( c>=‘0’&&c<=‘9’)
              {
            count++;
        }
    }
    return count;
} 
@end
技巧:可以在類方法裏調用對象方法,也可以在對象方法裏調用類的方法
類庫:很多類的集合 包含它分類的頭文件 就可以使用別人寫好的東西了

七、 類的深入

知識點

1.類的本質

1)實際上類也是一個對象,那麼這個對象的類型是什麼?是Class類型,Class裏已經包含* 裏;簡稱類對象
2)利用Class 創建 Person類對象
3)利用Person類對象,創建 Person類型的 對象 Person *p=[Person new];
4)獲取內存中的類對象:Class c=[p class]; //打印地址:%p;
5)獲取內存中的類對象2:Class c=[Person class];//和4)結果是一樣的

2.類對象的使用

1)調用類方法 + (void)test;
一般:利用類名 調用 [Person test];//類名就代表類對象
現在:Class c=[p class]; [c test];//用類對象調用
2)創建對象:Class c=[p class]; Person *p=[[c new] init];
3)一個類在內存中只擁有一份存儲空間,這個空間就叫類對象

3.類的加載和初始化

1)類的加載:在加載時,調用+ (void)load;這個類方法。由系統自動調用(當程序用沒用類時,都會做這件事)://程序一啓動加載類時
2)利用這個特性,來監聽
3)當程序使用類時,又會做更深調用:+(void)initialize;

4)測試,重寫這些類方法打印下
5)分類category裏,也會具有上述特性,優先選擇分類的初始化,類的初始方法不再調用;但是加載時,類和分類都會加載

6)當程序啓動時,就會加載項目中所有類和分類,而且加載後會調用每一個類和分類的+load方法,只會調用一次
7)當第一次使用某個類時,就會調用當前類的+initialize方法

8)先加載父類,再加載子類(先調用父類的+load再調用子類的+load)先加載原始類,再加載分類
當有分類時,分類優先調用+initialize,類不再調用+initialize)

9)想類第一次使用的時候,做些事情;這時就利用+initialize方法 //監聽

代碼舉例

#import "Person.h"

@implementation Person
+ (void)test
{
    NSLog(@"調用了test方法");
}


// 當程序啓動的時候,就會加載一次項目中所有的類。類加載完畢後就會調用+load方法
+ (void)load
{
    NSLog(@"Person---load");
}

// 當第一次使用這個類的時候,就會調用一次+initialize方法
+ (void)initialize
{
    NSLog(@"Person-initialize");
}

@end
//對應的main函數 注意把相應的頭文件導入
int main()
{
    // 利用Person這個類創建了2個Person類型的對象
    Person *p = [[Person alloc] init];

    Person *p2 = [[Person alloc] init];

    Person *p3 = [[Person alloc] init];

    // 獲取內存中的類對象
    Class c = [p class];

    Class c2 = [p2 class];

    // 獲取內存中的類對象
    Class c3 = [Person class];


    NSLog(@"c=%p, c2=%p, c3=%p", c, c2, c3);
}

八、 description方法

知識點

description方法:在NSObject.h文件裏可以找到

1.一種是-開頭 類的
2.一種是+開頭 對象的
3.需求:一個類的所有屬性打印出來
方法1:NSLog(@“%@”,p);//打印OC對象,默認打印的時類名和對象地址;但是打印字符串,打印的卻是字符串???;不能滿足需求
原理:首先去調用對象p的-description方法,這個方法的返回值(NSString *),NSLog讓這個返回值顯示在屏幕上

-description方法默認返回的時 類名+內存地址

方法2:重寫description方法來覆蓋父類NSObject的description
-(NSString *)description()
{
    return @“13333”;
}
//實現需求
-(NSString *)description()//由NSLog的p調用;決定實例對象的輸出結果
{
    return [NSString stringWithFomat(@“name=%d”,_name)];
}
4.+開頭的description
需求:拿到類對象後,想輸出類對象時,
打印時,會先調用類的+description方法,拿到這個的返回值,顯示在屏幕上;默認返回值是類名;所以這個方法決定了類對象的輸出結果
5.總之重寫description可以更改輸出樣式,注意不能在這個方法裏用NSLog,否則會造成死循環

九、 NSLog

知識點

1*指針變量的地址NSLog(@“%@”,&p)和p裏存儲的對象地址NSLog(@“%@”,p)不是一個概念
2*下劃線下劃線 __LINE__//輸出行號;這個在文檔幫助裏的 Objctive-C→improved log。。。文件裏可以找到
3*NSLog輸出C語言字符串(char= “ddd就”)時,不能有中文,否則輸不出任何東西
4*__func__:輸出當前函數名
5*__FILE__:輸出源文件名
6*_cmd :代表着當前方法的SEL
// 下面的代碼會引發死循環
- (void)test {
    [self performSelector:_cmd];
}

十、 SEL

一種數據類型:SEL:一個SEL數據就代表一個方法

知識點

1.方法本身是怎麼存的???
首先分配存儲空間給這個類,類裏面有個方法列表,但是這些方法是怎麼存的呢?
注意:每一個方法在內存中都有一個SEL的數據和它對應。
方法調用:利用對象的isa找到它的類,然後去找這個方法
2.程序首先會把這個test包裝成SEL類型數據,通過這個數據去找到這個方法地址,
最終通過這個地址找到所要調用方法,顯然這個SEL數據裏有方法的地址
注意:有個緩存列表存儲上次查詢後的結果,所以先到緩存去找,找不到,再去內存去找

3.怎麼創建SEL數據:SEL s=@selector(方法名:);//有參數的方法 的 方法名是由冒號:的;然後可以用%d 輸出
4.通過SEL間接調用方法:[p perfomSelector:s] //可以傳參的 WithObject(id)特別注意→_→:有參數的方法 的 方法名是由冒號:的
5.打印字符串:%@
6.SEL:@selector的前三個字母的大寫,它就是對方法的一個包裝,所以可以通過它也能找到方法
7.方法都存在類對象中的

9.每個方法內部都有一個SEL類型的變量:_cmd//它代表當前方法;要打印出來它的值需要先轉換成字符串 NSStringFormSelector(_cmd);
10.在方法裏寫:[self performSelector:_cmd];//會自己調用自己,陷入死循環
11.SEL其實是對方法的一種包裝,將方法包裝成一個SEL類型的數據,去找對應的方法地址。找到方法地址就可以調用方法
12.調用的方法很頻繁時,可以直接把方法地址搞過來,直接去找到這個方法。高效
13.說的發消息就是發一個SEL類型的數據,根據這個數據找到方法的地址找到方法。所以本質上消息就是SEL。

代碼舉例

#import <Foundation/Foundation.h>
#import "Person.h"

int main()
{
    Person *p = [[Person alloc] init];

    [p test2];

    NSString *name = @"test2";

    SEL s = NSSelectorFromString(name);//把test2包裝成SEL類型的數據

    [p performSelector:s];//根據SEL數據找到對應的方法地址

    return 0;
}
發佈了36 篇原創文章 · 獲贊 1 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章