溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

怎么進行Objective-C的入門

發(fā)布時間:2021-11-29 09:17:17 來源:億速云 閱讀:138 作者:柒染 欄目:開發(fā)技術

怎么進行Objective-C的入門,很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細講解,有這方面需求的人可以來學習下,希望你能有所收獲。

    前言

    Objective-C(下面簡稱OC)是由C語言和Smalltalk擴展出來的,是C語言的超集,最大的區(qū)別是OC是面向?qū)ο蟮?,其火星文寫法對于之前從事Java開發(fā)的同學頗感蛋疼,OC最大特點之一是使用“消息結構”而不是“函數(shù)調(diào)用”,所以在運行時執(zhí)行的代碼由運行環(huán)境決定,而Java是由編譯器決定。個人感覺有關于IOS學習的文章相較于Android質(zhì)量較低,有可能是蘋果系統(tǒng)封閉的原因,本文側重介紹常用的語法,通過對比Java并結合本人入門的過程和經(jīng)驗,幫助有需求的同學快速掌握OC基本編程,為IOS的入門奠定語言基礎。下面首先是寫出第一行代碼,恭喜正式進入OC學習階段。

    int main(int argc, char *argv[])
    {
        @autoreleasepool //創(chuàng)建自動內(nèi)存釋放池
        {
        	//打印輸出
            NSLog(@"hello world ios!");
            return 0;
        }
    }

    下面介紹OC代碼的文件擴展名:

    文件擴展名類型
    .h頭文件,作用是對類、屬性、變量、函數(shù)等的聲明
    .m實現(xiàn)文件,對頭文件的生命實現(xiàn)或者擴展
    .mm實現(xiàn)文件,一般是C++代碼

    如果實現(xiàn)文件需要引入頭文件時,推薦使用#import,跟#include作用相同,優(yōu)化了確保相同文件只會被引入一次,所以傾向用#import。

    基本數(shù)據(jù)類型

    包括:int float double char

    類型字節(jié)數(shù)格式化輸出
    char1%c
    int4%i,%x,%o
    unsigned int4%i,%x,%o
    short int2%hi,%hx,%ho
    unsigned short int2%hi,%hx,%ho
    long int8%li,%lx,%lo
    unsigned long int8%lu,%lx,%lo
    long long int8%lli,%llx,%llo
    unsigned long long int8%llu,%llx,%llo
    float4%f
    double8%f
    long double16%Lf

    其他數(shù)據(jù)類型

    id類型

    可以存放任何數(shù)據(jù)類型的對象,類似Java中的Object類,其被定義為指向?qū)ο蟮闹羔槪ū旧砭褪侵羔樍耍?,故定義比如id instance = nil;id類型是多態(tài)和動態(tài)綁定的基礎。

    BOOL類型

    布爾值為YES/NO或1/0。Java對應是true/false

    nil和Nil

    nil相當于Java中的null,表示一個對象,這個對象的指針指向空。Nil是定義一個指向空的類而不是對象。

    NSString(不可變字符串)

    字符串是非常重要常用的,務必要掌握常用的基礎用法,包括創(chuàng)建、截取、遍歷、比較、大小寫轉換、搜索等,語義跟基本類似Java。

    //字符串
    NSString *str1 = @"ABC3456789";
    //拼接成新的字符串
     NSString *str2 = [str1 stringByAppendingString:@"wwww"];
    NSLog(@"str = %@", str2);
    //遍歷
    for (int i = 0; i < [str2 length]; i++) {
        char temp = [str2 characterAtIndex:i];
        NSLog(@"字符串第 %d 位輸出 %c", i, temp);
    }
    //比較
    // sEqualToString方法 :比較字符串是否完全相等,大小寫不一樣也無法完全匹配。
    //hasPrefixe方法:逐一匹配字符串頭部。haSuffix方法:匹配字符串的尾部
    if ([str2 isEqualToString:str1]) {
        NSLog(@"相等");
    }
    if ([str2 hasPrefix:@"www"]) {
        NSLog(@"有該頭部");
    }
    if ([str2 hasSuffix:@"www"]) {
        NSLog(@"有該尾部");
    }
    if ([str2 compare:str options:NSCaseInsensitiveSearch | NSNumericSearch] == NSOrderedSame) {
    }
    NSLog(@"比較結果:%d", [str2 caseInsensitiveCompare:str1]);
    //大小寫轉換
    NSLog(@"str3轉大寫:%@",[str2 uppercaseString]);
    NSLog(@"str3轉小寫:%@",[str2 lowercaseString]);
    NSLog(@"str3首字母轉大寫:%@",[str2 capitalizedString]);
    //字符串截取
    NSRange rang = NSMakeRange(2, 2);
    NSLog(@"str3截取:%@",[str2 substringWithRange:rang]);
    //搜索
    NSRange rang1 = [str2 rangeOfString:@"www"];
    NSLog(@"location: %d,length: %d",rang1.location,rang1.length);
    //替換
    //全部替換
    NSString *str3 = [str2 stringByReplacingOccurrencesOfString:@" " withString:@"@"];
    NSLog(@"替換后字符串為%@", str3);
    //局部替換
    NSString *str4 = [str2 stringByReplacingCharactersInRange:rang withString:@"met"];
    NSLog(@"替換后字符串為%@", str4);
    NSMutableString(可變字符串)

    創(chuàng)建對象的基本寫法是[[NSMutableString alloc]init],*號代表對象,[]代表方法調(diào)用,只能通過類或者對象才能調(diào)用。[NSMutableString alloc]類似Java中new得到一個對象,然后再調(diào)用init初始化方法。

    		//創(chuàng)建對象并初始化
    		NSMutableString *mStr = [[NSMutableString alloc]init];
            //appendstring:向字符串尾部添加一個字符串。
            //appendFormat:向字符串尾部添加多個類型的字符串,可以添加任意數(shù)量與類型的字符串。
            [mStr appendString:@"hello world!"];
            NSLog(@"字符串創(chuàng)建%@", mStr);
            [mStr deleteCharactersInRange:[mStr rangeOfString:@"hello"]];
            //刪除
            NSLog(@"字符串刪除%@", mStr);
            //插入
            [mStr insertString:@"love you" atIndex: mStr.length];
            NSLog(@"字符串插入%@", mStr);
    NSInteger、NSUInteger和NSNumber

    NSInteger不是一個對象,而是基本數(shù)據(jù)類型中的typedef,NSUInteger是無符號的。 當需要使用int類型的變量時,推薦使用NSInteger,這樣不需要考慮設備是32位或者64位。NSNumber是一個類,用于包裝基本數(shù)據(jù)類型成為對象,可以理解為Java中的裝箱,為一些集合只能存放對象使用,通過字面量方式非常方便將基本數(shù)據(jù)類型轉成對應的對象。例如:

    //包裝
    NSNumber *intNumber = [[NSNumber alloc]initWithInt:43];
    //或者字面量方式
    NSNumber *intNumber1 = @43;
    //還原基本數(shù)據(jù)類型,解包
    NSLog(@"%d",[intNumber intValue]);

    集合

    集合不能接受nil,nil是作為集合結束標識符。

    1. NSArray(不可變)

    類似Java中的ArrayList,可以存儲不同類型的對象,一般情況下數(shù)組元素的類型是相同的,特點是有序、可重復。下面展示一位數(shù)組的基本操作: 

    //字面量創(chuàng)建方式
        NSArray *arr2 = @[@"aaa",@"bbbbb"];
    //工廠方法創(chuàng)建
        NSArray *array = [[NSArray alloc] initWithObjects:@"1", @"2", nil];
        //取最后一個元素
        [array lastObject];
    //    取第一個元素
        [array firstObject];
    //    數(shù)組是否包含某個元素
        [array containsObject:@"1"];
    //    數(shù)組的大小
        int count = (int) array.count;
    //    第一種方式遍歷
        for (int i = 0; i < count; i++) {
            NSString *_str = [array objectAtIndex:i];
        }

    那么數(shù)據(jù)要求是多維的呢?多維數(shù)組可以理解為數(shù)組的數(shù)組,通過嵌套的方式,創(chuàng)建如下:

    // 字面量創(chuàng)建二維數(shù)組并訪問
    NSArray *arr2 = @[@[@11, @12, @13], @[@21, @22, @23], @[@31, @32, @33]];
    // 字面量訪問方式(推薦)
    NSLog(@"arr2[2][2]:%@", arr2[2][2]);
    // 數(shù)組對象函數(shù)訪問
    NSLog(@"arr2[2][2]:%@", [[arr2 objectAtIndex:2] objectAtIndex:2]);

    2. NSMutableArray(可變的)

    派生于NSArray,理解為動態(tài)數(shù)組,提供增加、刪除、插入、替換等語法糖。

    		//創(chuàng)建,當然還有其他方式
            NSMutableArray *mutableArr = [NSMutableArray arrayWithObjects:@"one",@"two",@"three", nil];
            //添加
            [mutableArr addObject:@"hello"];
            //替換
            [mutableArr replaceObjectAtIndex:2 withObject:@"tihuan"];
            //刪除
            [mutableArr removeObjectAtIndex:1];
            //插入
            [mutableArr insertObject:@"ios" atIndex:1];

    多維數(shù)組創(chuàng)建方式如下:

       		// 初始化作為列的數(shù)組,看做4列
    NSMutableArray *columnArray = [[NSMutableArray alloc]initWithCapacity:4];
    
    // 初始化2個一維數(shù)組,每個一維數(shù)組有4個元素,看做1行4列,2行加起來就是2行4列
    NSMutableArray *rowArray1 = [[NSMutableArray alloc]initWithCapacity:4];
    NSMutableArray *rowArray2 = [[NSMutableArray alloc]initWithCapacity:4];
    
    // 每個行依次增加數(shù)組元素
    // 第一行
    [rowArray1 addObject:@"11"];
    [rowArray1 addObject:@"12"];
    [rowArray1 addObject:@"13"];
    [rowArray1 addObject:@"14"];
    
    // 第二行
    [rowArray2 addObject:@"21"];
    [rowArray2 addObject:@"22"];
    [rowArray2 addObject:@"23"];
    [rowArray2 addObject:@"24"];
    
    // 分別打印數(shù)組
    NSLog(@"myRowArray1: %@", rowArray1);
    NSLog(@"myRowArray2: %@", rowArray2);
    NSLog(@"myColumnArray: %@", columnArray);

    字典

    類似于Java中的HashMap,是一種映射型數(shù)據(jù)結果,存儲鍵值對,有可變和不可變兩種類型。

    NSDictionary

    主要特點是不可變,如果集合初始化完成,將內(nèi)容無法修改,無序。

    	//標準創(chuàng)建
        NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:@"cat",@"name1",@"dog",@"name2", nil];
        //字面量創(chuàng)建
        NSDictionary *dict1 = @{@"name1":@"cat",@"name2":@"dog"};
    	//第一種遍歷
        for (NSString *key in [dict1 allKeys]) {
            NSLog(@"key: %@,value: %@", key, dict1[key]);
        }
        //第二種遍歷方式,通過遍歷器
        NSEnumerator *rator = [dict keyEnumerator];
        NSString *temp;
        while (temp = [rator nextObject]) {
            NSLog(@"%@", temp);
        }
        //獲取元素
    	dict1[@"name"];
    	[dict1 objectForKey:@"name"];
    	//集合元素的個數(shù)
    	NSInteger count = dict1.count;
    	//沙盒文件存儲和讀取Plist
    	[dict5 writeToFile:@"路徑" atomically:YES];
    	NSDictionary *dict7 = [NSDictionary dictionaryWithContentsOfFile:@"路徑"];

    NSMutableDictionary

    NSMutableDictionary是NSDictionary的子類。NSMutableDictionary是可變的,動態(tài)添加、更改、刪除元素,因此不能使用字面量方式(@{})來創(chuàng)建一個可變字典。如果是不可變字典,出現(xiàn)了同名的key,那么后面的key對應的值不會被保存,反之是可變字典,出現(xiàn)了同名的key,那么后面的值會覆蓋前面的值。

    //創(chuàng)建
    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
    //添加
    [dict setObject:@"dog" forKey:@"name"];
    [dict setValue:@"18" forKey:@"age"];
    //會將傳入字典中所有的鍵值對取出來添加到dict中
    [dict setValuesForKeysWithDictionary:@{@"name1":@"dog"}];
    //取元素
    [dict objectForKey:@"name"];
    dict[@"name"];
    //刪除
    [dict removeAllObjects];
    [dict removeObjectForKey:@"name"];
    [dict removeObjectsForKeys:@[@"name", @"age"]];
    //更新,如果利用setObject方法給已經(jīng)存在的key賦值,新值會覆蓋舊值
    [dict setObject:@"20" forKey:@"age"];
    dict[@"age"] = @"30";

    NSSet && NSMutableSet

    具有很好的存取和查找功能,與NSArray相比NSSet的元素沒有索引,特點是無序,不可重復,類似Java中的HashSet,其中NSMutableSet提供計算交并集的方法。

    NSSet存儲元素的過程:

    怎么進行Objective-C的入門

    注意:推薦使用字面量方式創(chuàng)建對象,可以縮短代碼長度,增加可讀性。但是在創(chuàng)建數(shù)組的時候要注意,如果含有nil就會拋異常,因為字面量實際上”語法糖“,效果等同于先創(chuàng)建一個數(shù)組,然后再把所有的對象添加進來,保證數(shù)組不添加nil。

    消息傳遞

    前言提到Objective-C最大特點之一是繼承了Smalltalk消息傳遞模型,因此在OC中的方法調(diào)用準備的說法是消息傳遞,類別與消息關系松散,調(diào)用方法是給對象發(fā)送消息,而方法是對消息的回應,所有消息的處理直到運行時(即runtime)才會動態(tài)確定,并交由類自行決定如何處理收到的消息??偨Y是一個類不保證一定會回應收到的消息,當收到的一個無法處理的消息,會拋出異常。

    Java或者C++方法調(diào)用:

    obj.method(argument);

    OC方法調(diào)用:

    [obj method: argument];

    我們都知道在Java或者C++中,如果類沒有定義method方法,那么編譯肯定不會通過,但是在OC中,理解是發(fā)送method的消息給obj,obj收到消息后再決定如何回應消息,如果類內(nèi)定義了method方法則運行,反之不存在運行期拋出異常。

    所有面向?qū)ο蟮木幊潭加蓄惖母拍?,用于封裝數(shù)據(jù),這樣的語言特性都有封裝、繼承和多態(tài)。OC對象是類在運行期的實例,包含了類聲明的實例變量、內(nèi)存拷貝、類成員的指針等。由于OC是C語言的超集,類由兩個部分組成,分別是定義(interface)和實現(xiàn)(implementation),下面舉個?。新建一個People類,@interface是接口聲明的開始,@end終止結束,所有的OC編譯指令都是以”@“開始的。類的實現(xiàn)是通過@implementation指令開頭以@end結束。對應People.h和People.m兩份文件,下圖是類聲明(People.h)的展示,主要包括繼承關系、成員變量、屬性、方法聲明等,方法的具體實現(xiàn)是在People.m。

    怎么進行Objective-C的入門

    下圖是方法聲明的展示:

    怎么進行Objective-C的入門

    當然不止Interface區(qū)塊可以定義變量,Implementation區(qū)塊也可以定義,兩者區(qū)別是訪問權限不一。

    前者默認權限為protected,而implementation區(qū)塊的實體變量則默認為private,所以類別私有可以放在implementation區(qū)塊。

    訪問修飾符

    • @public:任何位置可以訪問。

    • @protected:默認情況下成員變量的修飾符。

    • @private:變量只限于聲明它的類訪問,不允許被繼承。

    • @package:限定在當前包內(nèi),類似于Java包的概念。

    屬性

    成員變量是給類內(nèi)使用的,屬性是作為類外訪問成員變量的接口,用于封裝對象的數(shù)據(jù),通過@property聲明,編譯器自動生成setter和getter方法,此過程稱為”自動合成“。類實現(xiàn)文件中@synthesize語法可以指定實例變量的名字,一般不推薦這樣做。@dynamic語法是告訴編譯器不要自動合成,在OC中訪問修飾符很少用到,主要是靠聲明屬性取值。

    屬性有五個常用的特質(zhì)修飾:

    assign:針對基本數(shù)據(jù)類型賦值操作。
    strong:定義一種”擁有關系“,屬性設置新值時,先保留新值,并釋放舊值,然后再將新值設置。
    weak:跟strong相反,屬性所指的對象銷毀時,屬性值也會清空。
    copy:設置方法不保留新值,而是拷貝一份。
    nonatomic:非原子,非線程安全類型。

    Q&A:為什么NSString 、 NSArray、 NSDictionary的屬性要用copy,集合的深淺拷貝是怎樣的?

    copy屬性作用是為變量賦值的時候系統(tǒng)自動copy一份內(nèi)存出來,修改新變量不會影響舊變量。在Apple規(guī)范中,NSString,NSArray,NSDictonary,推薦使用copy屬性,而其NSMubtableString,NSMutableArray, NSMutableDictonary屬性則使用strong屬性。

    NSString *sourceString = [NSString stringWithFormat:@"hello ios"];
    //不產(chǎn)生新的內(nèi)存空間
    NSString *copyStr = [sourceString copy];
    //產(chǎn)生新的內(nèi)存空間
    NSMutableString *mutableStr = [sourceString mutableCopy];
    NSLog(@"sourceString : %@   %p",sourceString,sourceString);
    NSLog(@"copyStr : %@    %p",copyStr,copyStr);
    NSLog(@"mutableStr : %@     %p",mutableStr,mutableStr);

    怎么進行Objective-C的入門

    使用strong這個屬性就有可能指向一個可變對象,如果這個可變對象在外部被修改了,那么會影響該屬性。例如:

    //代碼塊   
    NSMutableString *string = [NSMutableString stringWithString:@"origin"];//copy
    NSString *stringCopy = [string copy];
    NSLog(@"string address is: %p",string);
    NSLog(@"stringCopy address is: %p",stringCopy);

    結果:內(nèi)存地址不同

    怎么進行Objective-C的入門

    NSMutableString *string = [NSMutableString stringWithString:@"origin"];
    //NSString *stringCopy = [string copy];
    NSString *stringCopy = string;
    [string appendString:@"change"];
    NSLog(@"string address is: %p",string);
    NSLog(@"stringCopy address is: %p",stringCopy);

    結果:內(nèi)存地址相同

    怎么進行Objective-C的入門

    結論:

    可變對象指向不可變對象會導致不可變對象的值被篡改,所以需要copy屬性。用@property聲明NSString、NSArray、NSDictionary 經(jīng)常使用copy關鍵字,是因為他們有對應的可變類型NSMutableString、NSMutableArray、NSMutableDictionary,彼此之間可能進行賦值操作,為了不可變對象中的內(nèi)容不會被無意間變動,應該在設置新屬性值時拷貝一份。

    淺拷貝:

    在Java中淺拷貝如果是基本數(shù)據(jù),則拷貝的是基本數(shù)據(jù)的值;如果是對象,則拷貝的是內(nèi)存地址,修改該對象會影響另外一個對象。在OC中是對指針的拷貝,拷貝后的指針和原本對象的指針指向同一塊內(nèi)存地址,故同樣會相互影響。

    怎么進行Objective-C的入門

    深拷貝:

    OC中不僅拷貝指針,而且拷貝指針指向的內(nèi)容,指針指向不同的內(nèi)存地址,故修改不會相互影響原本對象。

    怎么進行Objective-C的入門

    非集合類對象中:對immutable對象進行copy操作,是指針復制(淺拷貝),mutableCopy操作時內(nèi)容復制;對mutable對象進行copy和mutableCopy都是內(nèi)容復制(深拷貝)。

    方法

    通過”+“、”-“分別聲明類方法和實例方法,方法如果帶有多個參數(shù),參數(shù)在方法名之后接冒號定義,多個參數(shù)由空格隔開,如果參數(shù)個數(shù)可變,使用逗號接省略號。例如:

    //無參數(shù)
    - (void)print;
    //有參數(shù)
    - (void)print:(int)a andB:(int)b;

    構造方法

    第一種是重寫init方法,第二種是自定義。

    /**
     重寫初始化方法
     **/
    - (instancetype)init
    {
        self = [super init];
        if (self) {
            _peopleName = @"hello ios";
        }
        return self;
    }
    
    /**
     自定義初始化方法
     **/
    - (instancetype)initWithNameAndAge:(NSString *)name andAge:(int)age
    {
        self = [super init];
        if (self) {
            _peopleName = name;
            _peopleAge = age;
        }
        return self;
    }

    創(chuàng)建類對象

    所有對象和類的引用都是通過指針實現(xiàn),嚴格地說指針就是一個地址,是一個常量,而指針變量可以被賦值不同的指針值,創(chuàng)建的對象就是一個指針變量,通過[People alloc]創(chuàng)建一個People對象,分配了內(nèi)存,init是初始化對象。構造方法有兩種方式,第一種是重寫init方法,第二種是自定義。

    People *p1 = [[People alloc] init];
    //調(diào)用自定義的構造方法
    People *p3 = [[People alloc] initWithNameAndAge:@"mingzi" andAge:12];
    //調(diào)用方法
    [p3 print];

    在OC 2.0中,如果創(chuàng)建的對象不需要參數(shù),可以直接使用new:

    People *p1 = [People new];

    self

    作為OC的一個關鍵字,代表當前類的對象,類似Java中的this,最大的作用是讓類中的一個方法調(diào)用該類另外一個方法或者成員變量,可以理解”當前類誰調(diào)用了這個方法,self就代表誰“。

    繼承

    同Java一樣只能單繼承,只允許最多有一個直接父類。例如:定義一個父類Computer和子類MacBook。注意方法重寫類似Java,子類要重寫父類方法不需要重新聲明重寫方法,在實現(xiàn)部分直接重寫目標方法即可。如果需要子類調(diào)用父類的方法,可以通過super關鍵字調(diào)用。

    //Computer.h文件
    #import <Foundation/Foundation.h>
    @interface Computer : NSObject
    @property(nonatomic,strong)NSString *name;
    -(void)calculate;
    @end
    
    //  Computer.m
    #import "Computer.h"
    @implementation Computer
    @synthesize name;
    -(void) calculate{
        NSLog(@"i can calculate");
    }
    @end
    
    //  MacBook.h
    #import "Computer.h"
    @interface MacBook : Computer
    @end
    
    //  MacBook.m
    #import "MacBook.h"
    @implementation MacBook
    @end
    
    //main.m
    int main(int argc, char *argv[])
    {
        @autoreleasepool
        {
            MacBook *macBook = [[MacBook alloc] init];
            macBook.name = @"mac";
            [macBook calculate];
        }
    }

    多態(tài)

    封裝、繼承和多態(tài)是面向?qū)ο缶幊陶Z言的三大特性,OC的多態(tài)是不同對象對同一消息的不同響應方式,實際過程主要分為三種:

    • 繼承

    • 重寫

    • 指向子類的指針指向父類

    可以看出跟Java的多態(tài)類似,理解起來應該比較容易,注意是沒有方法重載的,在OC中不允許。

    Runtime

    實例:用Runtime新增一個類Person, person有name屬性,有sayHi方法

    #import <UIKit/UIKit.h>
    #import "AppDelegate.h"
    #import <objc/runtime.h>
    #import <objc/message.h>
    void sayHi(id self, IMP _cmd, id some)
    {
        //self指的是調(diào)用該方法傳過來的類
        NSLog(@"%@說:%@,我%@歲", [self valueForKey:@"name"], some, object_getIvar(self, class_getInstanceVariable([self class], "_age")));
    }
    
    int main(int argc, char *argv[])
    {
        @autoreleasepool
        {
            //該方法動態(tài)創(chuàng)建一個類,arg1:繼承自哪個類 arg2:新建類的名稱 arg3:extraBytes
            Class Person = objc_allocateClassPair([NSObject class], "Person", 0);
            //添加兩個實例變量name和age,arg2:變量名稱,arg3:內(nèi)存地址大小,arg5:變量類型
            class_addIvar(Person, "_name", sizeof(NSString *), log2(sizeof(NSString *)), @encode(NSString *));
            class_addIvar(Person, "_age", sizeof(int), sizeof(int), @encode(int));
            //注冊方法名
            SEL s = sel_registerName("say:");
            //arg3:IMP是“implementation”的縮寫,這個函數(shù)指針決定了最終執(zhí)行哪段代碼
            //arg4:方法的參數(shù)及返回值
            class_addMethod(Person, s, (IMP)sayHi, "v@:@");
            //通過該類創(chuàng)建一個實體的對象
            id peopleInstance = [[Person alloc]init];
            //給對象的 name 實例變量賦值,下面是第二種賦值方式
            [peopleInstance setValue:@"XQM" forKey:@"name"];
            //Ivar nameIvar = class_getInstanceVariable(Person, "_name");
            //object_setIvar(peopleInstance, nameIvar, @"XQM");
            //獲取實例變量
            Ivar ageIvar = class_getInstanceVariable(Person, "_age");
            //為變量賦值
            object_setIvar(peopleInstance, ageIvar, @21);
            //調(diào)用sayHi方法,arg2:注冊指定的方法;arg3:帶上有一個字符串的參數(shù)
            ((void(*)(id, SEL, id))objc_msgSend)(peopleInstance, s, @"大家好");
            //調(diào)用完成,將對象置為空
            peopleInstance = nil;
            //通過 objc 銷毀類,銷毀的是一個類不是對象
            objc_disposeClassPair(Person);
        }
    }

    主要流程是:

    定義類的方法->objc_allocateClassPair創(chuàng)建類->class_addIvar給類添加成員變量->sel_registerName注冊方法名->class_addMethod給類添加定義的方法->注冊該類->創(chuàng)建類對象->class_getInstanceVariable獲取成員變量,并通過object_setIvar賦值->objc_msgSend調(diào)用方法->釋放對象,銷毀類

    Category(類別)

    Objective-C借用并擴展了Smalltalk實現(xiàn)中的"分類"概念,用以幫助達到分解代碼的目的。類別主要特點是不能增加屬性或者成員變量、增加類功能和分離類實現(xiàn),舉個例子: 在UIImageView增加了圖片異步加載的功能

    @interface UIImageView (ImageViewLoader) <AysncImageDownloaderDelegate>
    - (void)setOnlineImage:(NSString *)url placeholderImage:(UIImage *)image withRow:(NSNumber *)row;
    @end
    
    @implementation UIImageView (ImageViewLoader)
    
    - (void)setOnlineImage:(NSString *)url placeholderImage:(UIImage *)image withRow:(NSNumber *)row;
    {
        self.image = image;
        AsyncImageDownLoader *downloader = [AsyncImageDownLoader sharedImageDownloader];
        [downloader startWithUrl:url delegate:self withRow:row];
    }
    @end

    Extension(拓展)

    拓展也經(jīng)常用到,主要特點是增加ivar、用于接口分離等。例如:ViewController的實現(xiàn)文件增加@interface ViewController (),支持定義屬性等。

    @interface ViewController ()
    @property (nonatomic, copy) block b;
    @end
    
    @implementation ViewController
    @end

    異常處理

    OC的異常處理極其類似Java中的,包括4個指示符,分別是@try、@catch、@throw、@finally??赡艽嬖诋惓5拇a寫在@try塊,異常處理邏輯寫在@catch,@finally塊的代碼總是要執(zhí)行的,@throw作用是拋出異常。

    協(xié)議

    類似Java中的接口(interface),類似多重繼承功能,支持協(xié)議繼承協(xié)議,通過定義一系列方法,然后由遵從協(xié)議的類實現(xiàn)這些方法,協(xié)議方法可以用@optional關鍵字標記為可選,@required關鍵字標記為必選,編譯器會出現(xiàn)檢查警告,一般來說還是可以編譯通過。下面看下語法:

    @protocol ClickDelegate
    - (void)click;
    - (void)unclick;
    @end

    協(xié)議最常應用在委托,分為委托方和代理方,委托方負責定義協(xié)議、通過id類型持有協(xié)議和調(diào)用協(xié)議的方法,而代理方則遵從協(xié)議、設置協(xié)議代理對象以及實現(xiàn)協(xié)議方法即可。

    block

    類似Java中的Lambda表達式,比較復雜,筆者的理解還未達到一定解說程度,所以這里先不做解釋,放到后續(xù)的文章中介紹。

    內(nèi)存管理

    Java的內(nèi)存管理是由垃圾回收器負責,OC中引入自動引用計數(shù)(ARC),內(nèi)存管理交由編譯器決定。引用計數(shù)是每個對象都有一個計數(shù)器,如果對象繼續(xù)存活,計數(shù)器遞增其引用計數(shù),用完之后遞減引用計數(shù),如果計數(shù)變?yōu)?,表示對象可以被釋放了。NSObject協(xié)議聲明了Retain、release和autorelease方法用于操作計數(shù)器,分別是遞增、遞減、自動釋放操作,所有的對象都是收集器的工作對象。

    ARC:自動引用計數(shù),編譯器自動生成retain/release
    MRC:手動管理引用計數(shù),舊版本使用
    autoreleasepool:延遲自動釋放

    strong/weak/assgin最佳實踐

    基本類型:assgin;
    delegate->week;
    集合和block用copy;
    其他用strong;
    block中的self用weak打破循環(huán)引用。

    看完上述內(nèi)容是否對您有幫助呢?如果還想對相關知識有進一步的了解或閱讀更多相關文章,請關注億速云行業(yè)資訊頻道,感謝您對億速云的支持。

    向AI問一下細節(jié)

    免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。

    AI