技術(shù)
中級(jí)
Block
1.block的實(shí)質(zhì)是什么?一共有幾種block?都是什么情況下生成的?
block定義:
struct Block_descriptor {
unsigned long int reserved;
unsigned long int size;
void (*copy)(void *dst, void *src);
void (*dispose)(void *);
};
struct Block_layout {
void *isa;
int flags;
int reserved;
void (*invoke)(void *, ...);
struct Block_descriptor *descriptor;
/* Imported variables. */
};
Clang(LLVM編譯器)將含有Block語(yǔ)法的源代碼轉(zhuǎn)換為我們可讀源代碼的功能造锅。通過(guò)“-rewrite-objc”選項(xiàng)就能將含有Block語(yǔ)法的源代碼變換為C++的源代碼(本質(zhì)是使用了struct結(jié)構(gòu)的C語(yǔ)言源代碼)
而B(niǎo)lock實(shí)質(zhì)上就是Objective-C對(duì)象;
根據(jù)isa指針,block一共有3種類型的block
- _NSConcreteGlobalBlock 全局靜態(tài)
- _NSConcreteStackBlock 保存在棧中廉邑,出函數(shù)作用域就銷毀
- _NSConcreteMallocBlock 保存在堆中哥蔚,retainCount == 0銷毀而ARC和MRC中,還略有不同;
《Objective-C高級(jí)編程》Blocks 閱讀筆記 item2(Block的實(shí)質(zhì))
2.為什么在默認(rèn)情況下無(wú)法修改被block捕獲的變量蛛蒙? __block都做了什么糙箍?
Block只捕獲Block中會(huì)用到的變量。由于只捕獲了自動(dòng)變量(自動(dòng)變量是以值傳遞方式傳遞到Block的構(gòu)造函數(shù)里面)的值牵祟,并非內(nèi)存地址深夯,所以Block內(nèi)部不能改變自動(dòng)變量的值。Block捕獲的外部變量可以改變值的是靜態(tài)變量诺苹,靜態(tài)全局變量咕晋,全局變量。
深入研究Block捕獲外部變量和__block實(shí)現(xiàn)原理
3.模擬一下循環(huán)引用的一個(gè)情況收奔?block實(shí)現(xiàn)界面反向傳值如何實(shí)現(xiàn)掌呜?
#import "ViewController.h"
#import "Student.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
Student *student = [[Student alloc]init];
student.name = @"Hello World";
student.study = ^{
NSLog(@"my name is = %@",student.name);
};
}
student的study的Block里面強(qiáng)引用了student自身。根據(jù)上篇文章的分析筹淫,可以知道站辉,_NSConcreteMallocBlock捕獲了外部的對(duì)象,會(huì)在內(nèi)部持有它损姜。retainCount值會(huì)加一饰剥。
更多例子參考:
iOS循環(huán)引用問(wèn)題集合
block界面反向傳值實(shí)例:
1、在第二個(gè)視圖控制器的.h文件中定義聲明Block屬性:
// NextViewController.h
// 定義block
@property (nonatomic,copy) void (^NextViewControllerBlock)
(NSString *tfText);
// NextViewController.m
@interface NextViewController ()
@property (weak, nonatomic) IBOutlet UITextField *inputTF;
@end
- (IBAction)BtnAction:(id)sender {
//判斷block是否為空
if (self.NextViewControllerBlock) {
self.NextViewControllerBlock(self.inputTF.text);
}
[self.navigationController popViewControllerAnimated:YES];
}
2摧阅、在第一個(gè)視圖中獲得第二個(gè)視圖控制器汰蓉,并且用第二個(gè)視圖控制器來(lái)調(diào)用定義的屬性:
// AViewController.m
@interface AViewController ()
@property (weak, nonatomic) IBOutlet UILabel *nextVCInfoLabel;
@end
- (IBAction)btnClicked:(id)sender {
NextViewController *nextVC = [[NextViewController alloc]init];
nextVC.NextViewControllerBlock = ^(NSString *tfText){
self.nextVCInfoLabel.text = tfText;
};
[self.navigationController pushViewController:nextVC animated:YES];
}
Runtime
1.objc在向一個(gè)對(duì)象發(fā)送消息時(shí),發(fā)生了什么棒卷?
Objc Runtime使得C具有了面向?qū)ο竽芰四酰诔绦蜻\(yùn)行時(shí)創(chuàng)建,檢查比规,修改類若厚、對(duì)象和它們的方法,可以使用runtime的一系列方法實(shí)現(xiàn)蜒什。
附上OC中一個(gè)類的底層數(shù)據(jù)結(jié)構(gòu):
mac電腦上的路徑/usr/include/objc/runtime.h
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY; //isa指針指向Meta Class测秸,因?yàn)镺bjc的類的本身也是一個(gè)Object,為了處理這個(gè)關(guān)系,r untime就創(chuàng)造了Meta Class霎冯,當(dāng)給類發(fā)送[NSObject alloc]這樣消息時(shí)铃拇,實(shí)際上是把這個(gè)消息發(fā)給了Class Object
#if !__OBJC2__
Class super_class OBJC2_UNAVAILABLE; // 父類
const char *name OBJC2_UNAVAILABLE; // 類名
long version OBJC2_UNAVAILABLE; // 類的版本信息,默認(rèn)為0
long info OBJC2_UNAVAILABLE; // 類信息沈撞,供運(yùn)行期使用的一些位標(biāo)識(shí)
long instance_size OBJC2_UNAVAILABLE; // 該類的實(shí)例變量大小
struct objc_ivar_list *ivars OBJC2_UNAVAILABLE; // 該類的成員變量鏈表
struct objc_method_list **methodLists OBJC2_UNAVAILABLE; // 方法定義的鏈表
struct objc_cache *cache OBJC2_UNAVAILABLE; // 方法緩存慷荔,對(duì)象接到一個(gè)消息會(huì)根據(jù)isa指針查找消息對(duì)象,這時(shí)會(huì)在method Lists中遍歷缠俺,如果cache了显晶,常用的方法調(diào)用時(shí)就能夠提高調(diào)用的效率。
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE; // 協(xié)議鏈表
#endif
} OBJC2_UNAVAILABLE;
OC中一個(gè)類的對(duì)象實(shí)例的數(shù)據(jù)結(jié)構(gòu)(/usr/include/objc/objc.h)
typedef struct objc_class *Class;
/// Represents an instance of a class.
struct objc_object {
Class isa OBJC_ISA_AVAILABILITY;
};
/// A pointer to an instance of a class.
typedef struct objc_object *id;
就是定義了一個(gè)向object發(fā)送消息時(shí)晋修,Runtime庫(kù)會(huì)根據(jù)object的isa指針找到這個(gè)實(shí)例object所屬于的類吧碾,然后在類的方法列表以及父類方法列表尋找對(duì)應(yīng)的方法運(yùn)行。id是一個(gè)objc_object結(jié)構(gòu)類型的指針墓卦,這個(gè)類型的對(duì)象能夠轉(zhuǎn)換成任何一種對(duì)象倦春。
消息發(fā)送函數(shù):objc_msgSend
objc_msgSend()是[obj foo]的具體實(shí)現(xiàn);
在runtime中,objc_msgSend()是一個(gè)c函數(shù)落剪,[obj foo]會(huì)被翻譯成這樣的形式objc_msgSend(obj, foo)睁本。
- 去obj的對(duì)應(yīng)的類中找方法
- 先找緩存,找不到再去找方法列表
- 再找父類忠怖,如此向上傳遞
- 最后再找不到就要轉(zhuǎn)發(fā)
2.什么時(shí)候會(huì)報(bào)unrecognized selector錯(cuò)誤呢堰?iOS有哪些機(jī)制來(lái)避免走到這一步?
什么時(shí)候會(huì)報(bào)unrecognized selector的異常凡泣?
預(yù)防 app crash 之 unrecognized selector
3.能否向編譯后得到的類中增加實(shí)例變量枉疼?能否向運(yùn)行時(shí)創(chuàng)建的類中添加實(shí)例變量?為什么?
- 不能向編譯后得到的類中增加實(shí)例變量鞋拟;
- 能向運(yùn)行時(shí)創(chuàng)建的類中添加實(shí)例變量骂维;
解釋下:
- 因?yàn)榫幾g后的類已經(jīng)注冊(cè)在 runtime 中,類結(jié)構(gòu)體中的 objc_ivar_list 實(shí)例變量的鏈表 和 instance_size 實(shí)例變量的內(nèi)存大小已經(jīng)確定贺纲,同時(shí)runtime 會(huì)調(diào)用 class_setIvarLayout 或 class_setWeakIvarLayout 來(lái)處理 strong weak 引用航闺。所以不能向存在的類中添加實(shí)例變量;
- 運(yùn)行時(shí)創(chuàng)建的類是可以添加實(shí)例變量猴誊,調(diào)用 class_addIvar 函數(shù)潦刃。但是得在調(diào)用 objc_allocateClassPair 之后,objc_registerClassPair 之前懈叹,原因同上乖杠。
4.runtime如何實(shí)現(xiàn)weak變量的自動(dòng)置nil?
不需要澄成。
在ARC環(huán)境無(wú)論是強(qiáng)指針還是弱指針都無(wú)需在 dealloc 設(shè)置為 nil 滑黔, ARC 會(huì)自動(dòng)幫我們處理
即便是編譯器不幫我們做這些笆包,weak也不需要在 dealloc 中置nil:
正如上文的:runtime 如何實(shí)現(xiàn) weak 屬性 中提到的:
我們模擬下 weak 的 setter 方法,應(yīng)該如下:
- (void)setObject:(NSObject *)object
{
objc_setAssociatedObject(self, "object", object, OBJC_ASSOCIATION_ASSIGN);
[object cyl_runAtDealloc:^{
_object = nil;
}];
}
如果對(duì)cyl_runAtDealloc
的實(shí)現(xiàn)原理有興趣略荡,可以看一個(gè)小庫(kù),可以使用 CocoaPods 在項(xiàng)目中使用: CYLDeallocBlockExecutor
也即:
在屬性所指的對(duì)象遭到摧毀時(shí)歉胶,屬性值也會(huì)清空(nil out)汛兜。
5.給類添加一個(gè)屬性后,在類結(jié)構(gòu)體里哪些元素會(huì)發(fā)生變化通今?
class object/metaclass
咱們先看一下結(jié)構(gòu)體objc_class的定義
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class super_class OBJC2_UNAVAILABLE;
const char *name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
long info OBJC2_UNAVAILABLE;
long instance_size OBJC2_UNAVAILABLE;
struct objc_ivar_list *ivars OBJC2_UNAVAILABLE;
struct objc_method_list **methodLists OBJC2_UNAVAILABLE;
struct objc_cache *cache OBJC2_UNAVAILABLE;
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;
/* Use `Class` instead of `struct objc_class *` */
創(chuàng)建一個(gè)類屬性很簡(jiǎn)單粥谬,主要有以下幾個(gè)步驟:
- 使用@property (class)來(lái)聲明一個(gè)類屬性;
- 為類屬性創(chuàng)建一個(gè)存儲(chǔ)變量辫塌,通常為全局變量漏策;
- 實(shí)現(xiàn)類屬性的getter與setter方法,如果是只讀屬性臼氨,只需要實(shí)現(xiàn)getter方法掺喻。
類相當(dāng)于一個(gè)對(duì)象, 當(dāng)對(duì)象執(zhí)行這個(gè)方法即會(huì)發(fā)送一條消息, 之后根據(jù)isa指針查找消息對(duì)象,這時(shí)會(huì)在methodLists中遍歷储矩,如果cache了感耙,常用的方法調(diào)用時(shí)就能夠提高調(diào)用的效率。
RunLoop
1.runloop是來(lái)做什么的持隧?runloop和線程有什么關(guān)系即硼?主線程默認(rèn)開(kāi)啟了runloop么?子線程呢屡拨?
runloop和線程有什么關(guān)系只酥?
2.runloop的mode是用來(lái)做什么的?有幾種mode呀狼?
model 主要是用來(lái)指定事件在運(yùn)行循環(huán)中的優(yōu)先級(jí)的裂允,分為:
- NSDefaultRunLoopMode(kCFRunLoopDefaultMode):默認(rèn),空閑狀態(tài)
- UITrackingRunLoopMode:ScrollView滑動(dòng)時(shí)
- UIInitializationRunLoopMode:?jiǎn)?dòng)時(shí)
- NSRunLoopCommonModes(kCFRunLoopCommonModes):Mode集合
蘋(píng)果公開(kāi)提供的 Mode 有兩個(gè):
- NSDefaultRunLoopMode(kCFRunLoopDefaultMode)
- NSRunLoopCommonModes(kCFRunLoopCommonModes)
3.為什么把NSTimer對(duì)象以NSDefaultRunLoopMode(kCFRunLoopDefaultMode)添加到主運(yùn)行循環(huán)以后赠潦,滑動(dòng)scrollview的時(shí)候NSTimer卻不動(dòng)了叫胖?
RunLoop只能運(yùn)行在一種mode下,如果要換mode她奥,當(dāng)前的loop也需要停下重啟成新的瓮增。利用這個(gè)機(jī)制,ScrollView滾動(dòng)過(guò)程中NSDefaultRunLoopMode(kCFRunLoopDefaultMode)的mode會(huì)切換到UITrackingRunLoopMode來(lái)保證ScrollView的流暢滑動(dòng):只能在NSDefaultRunLoopMode模式下處理的事件會(huì)影響ScrollView的滑動(dòng)哩俭。
如果我們把一個(gè)NSTimer對(duì)象以NSDefaultRunLoopMode(kCFRunLoopDefaultMode)添加到主運(yùn)行循環(huán)中的時(shí)候, ScrollView滾動(dòng)過(guò)程中會(huì)因?yàn)閙ode的切換绷跑,而導(dǎo)致NSTimer將不再被調(diào)度。
同時(shí)因?yàn)閙ode還是可定制的凡资,所以:
Timer計(jì)時(shí)會(huì)被scrollView的滑動(dòng)影響的問(wèn)題可以通過(guò)將timer添加到NSRunLoopCommonModes(kCFRunLoopCommonModes)來(lái)解決砸捏。代碼如下:
// http://weibo.com/luohanchenyilong/ (微博@iOS程序犭袁)
// https://github.com/ChenYilong
//將timer添加到NSDefaultRunLoopMode中
[NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:@selector(timerTick:)
userInfo:nil
repeats:YES];
//然后再添加到NSRunLoopCommonModes里
NSTimer *timer = [NSTimer timerWithTimeInterval:1.0
target:self
selector:@selector(timerTick:)
userInfo:nil
repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
4. 蘋(píng)果是如何實(shí)現(xiàn)Autorelease Pool的谬运?
autoreleasepool 以一個(gè)隊(duì)列數(shù)組的形式實(shí)現(xiàn),主要通過(guò)下列三個(gè)函數(shù)完成.
objc_autoreleasepoolPush
objc_autoreleasepoolPop
-
objc_autorelease
看函數(shù)名就可以知道,對(duì) autorelease 分別執(zhí)行 push垦藏,和 pop 操作梆暖。銷毀對(duì)象時(shí)執(zhí)行release操作。
舉例說(shuō)明:我們都知道用類方法創(chuàng)建的對(duì)象都是 Autorelease 的掂骏,那么一旦 Person 出了作用域轰驳,當(dāng)在 Person 的 dealloc 方法中打上斷點(diǎn),我們就可以看到這樣的調(diào)用堆棧信息:
類結(jié)構(gòu)
1.isa指針弟灼?(對(duì)象的isa级解,類對(duì)象的isa,元類的isa都要說(shuō))
Objective-C 是一門(mén)面向?qū)ο蟮木幊陶Z(yǔ)言田绑。每一個(gè)對(duì)象都是一個(gè)類的實(shí)例勤哗。在objective-c語(yǔ)言的內(nèi)部,每一個(gè)對(duì)象都有一個(gè)名為 isa 的指針掩驱,指向該對(duì)象的類芒划。每一個(gè)類描述了一系列它的實(shí)例的特點(diǎn),包括成員變量的列表昙篙,成員函數(shù)的列表等腊状。每一個(gè)對(duì)象都可以接受消息,而對(duì)象能夠接收的消息列表是保存在它所對(duì)應(yīng)的類中苔可。
iOS class深入理解: 實(shí)例對(duì)象焚辅、類對(duì)象映屋、元類和isa指針
2.類方法(class method)和實(shí)例方法(instance method)有什么區(qū)別?
類方法同蜻,也稱靜態(tài)方法棚点,指的是用static關(guān)鍵字修飾的方法。此方法屬類本身的方法湾蔓,不屬于類的某一個(gè)實(shí)例(對(duì)象)瘫析。類方法中不可直接使用實(shí)例變量。其調(diào)用方式有三種:可直接調(diào)用默责、類名.方法名贬循、對(duì)象名.方法名。實(shí)例方法指的是不用static關(guān)鍵字修飾的方法桃序。每個(gè)實(shí)例對(duì)象都有自身的實(shí)例方法杖虾,互相獨(dú)立,不共享一個(gè)媒熊。其調(diào)用方式只能是對(duì)象名.方法名奇适。
- instance method 以減號(hào) "-" 開(kāi)頭
- class method 以加號(hào) “+” 開(kāi)頭坟比,相當(dāng)于static方法
區(qū)別:
靜態(tài)方法在程序開(kāi)始時(shí)生成內(nèi)存,實(shí)例方法在程序運(yùn)行中生成內(nèi)存,
所以靜態(tài)方法可以直接調(diào)用,實(shí)例方法要先成生實(shí)例,通過(guò)實(shí)例調(diào)用方法嚷往,靜態(tài)速度很快葛账,但是多了會(huì)占內(nèi)存。
靜態(tài)內(nèi)存是連續(xù)的,因?yàn)槭窃诔绦蜷_(kāi)始時(shí)就生成了,而實(shí)例申請(qǐng)的是離散的空間,所以當(dāng)然沒(méi)有靜態(tài)方法快皮仁,
而且靜態(tài)內(nèi)存是有限制的注竿,太多了程序會(huì)啟動(dòng)不了。
使用場(chǎng)景:
如果需要訪問(wèn)或者修改某個(gè)實(shí)例的成員變量時(shí)魂贬,將該方法定義成實(shí)例方法。
類方法正好相反裙顽,它不需要訪問(wèn)或者修改某個(gè)實(shí)例的成員變量付燥。
類方法一般用于實(shí)現(xiàn)一些工具方法,比如對(duì)某個(gè)對(duì)象進(jìn)行擴(kuò)展愈犹,或者實(shí)現(xiàn)單例键科。
類方法常駐內(nèi)存,實(shí)例方法不是漩怎,所以類方法效率高但占內(nèi)存勋颖。
類方法在堆上分配內(nèi)存,實(shí)例方法在堆棧上勋锤。
事實(shí)上所有的方法都不可能在堆或者堆棧上分配內(nèi)存饭玲,方法作為代碼是被加載到特殊的代碼內(nèi)存區(qū)域,這個(gè)內(nèi)存區(qū)域是不可寫(xiě)的叁执。
實(shí)例方法需要先創(chuàng)建實(shí)例才可以調(diào)用茄厘,比較麻煩,類方法不用谈宛,比較簡(jiǎn)單次哈。
事實(shí)上如果一個(gè)方法與他所在類型的實(shí)例無(wú)關(guān),那么它就應(yīng)該是靜態(tài)的吆录,決不會(huì)有人把它寫(xiě)成實(shí)例方法窑滞。所以所有的實(shí)例方法都與實(shí)例有關(guān),既然與實(shí)例有關(guān)恢筝,那么創(chuàng)建實(shí)例就是必然的步驟哀卫,沒(méi)有麻煩簡(jiǎn)單一說(shuō)。實(shí)際上上你可以把所有的實(shí)例方法都寫(xiě)成靜態(tài)的滋恬,將實(shí)例作為參數(shù)傳入即可聊训。
3.介紹一下分類,能用分類做什么恢氯??jī)?nèi)部是如何實(shí)現(xiàn)的带斑?它為什么會(huì)覆蓋掉原來(lái)的方法鼓寺?
類別(Category)主要有3個(gè)作用:
- 將類的實(shí)現(xiàn)分散到多個(gè)不同文件或多個(gè)不同框架中。
- 創(chuàng)建對(duì)私有方法的前向引用勋磕。
- 向?qū)ο筇砑臃钦絽f(xié)議妈候。
聲明:@interface 類名(分類名稱) @end
實(shí)現(xiàn):@implementation 類名(分類名稱) @end
注意:
(1)在分類只能增加方法,不能增加成員變量,如果要增加成員變量的話該考慮用繼承去實(shí)現(xiàn)
(2)在分類實(shí)現(xiàn)方法中可以訪問(wèn)類中的成員變量但是不能訪問(wèn)類中的屬性@property
(3)在分類中可以重新實(shí)現(xiàn)原類中的方法挂滓,但會(huì)將原類中的方法覆蓋而失效苦银。
因?yàn)樵趫?zhí)行對(duì)象成員方法的時(shí)候會(huì)優(yōu)先去分類中查找,然后再去原類中去查找赶站,最后去父類中去查找
(4)如果一個(gè)類有多個(gè)分類幔虏,而且分類中有同名的方法那么最后編譯的分類會(huì)將前面編譯的分類覆蓋而執(zhí)行輸出
// 另外一份解釋來(lái)自《招聘一個(gè)靠譜的 iOS》—參考答案(上)---24
// 類方法:
- 類方法是屬于類對(duì)象的
- 類方法只能通過(guò)類對(duì)象調(diào)用
- 類方法中的self是類對(duì)象
- 類方法可以調(diào)用其他的類方法
- 類方法中不能訪問(wèn)成員變量
- 類方法中不能直接調(diào)用對(duì)象方法
// 實(shí)例方法:
- 實(shí)例方法是屬于實(shí)例對(duì)象的
- 實(shí)例方法只能通過(guò)實(shí)例對(duì)象調(diào)用
- 實(shí)例方法中的self是實(shí)例對(duì)象
- 實(shí)例方法中可以訪問(wèn)成員變量
- 實(shí)例方法中直接調(diào)用實(shí)例方法
- 實(shí)例方法中也可以調(diào)用類方法(通過(guò)類名)
4.運(yùn)行時(shí)能增加成員變量么?能增加屬性么贝椿?如果能想括,如何增加?如果不能烙博,為什么瑟蜈?
Category中不能動(dòng)態(tài)添加成員變量;
在Objective-C提供的runtime函數(shù)中,確實(shí)有一個(gè)class_addIvar()函數(shù)用于給類添加成員變量渣窜,但是閱讀過(guò)蘋(píng)果的官方文檔的人應(yīng)該會(huì)看到:
This function may only be called after objc_allocateClassPair and before objc_registerClassPair. Adding an instance variable to an existing class is not supported.
大概的意思說(shuō)铺根,這個(gè)函數(shù)只能在“構(gòu)建一個(gè)類的過(guò)程中”調(diào)用。一旦完成類定義乔宿,就不能再添加成員變量了位迂。經(jīng)過(guò)編譯的類在程序啟動(dòng)后就被runtime加載,沒(méi)有機(jī)會(huì)調(diào)用addIvar予颤。程序在運(yùn)行時(shí)動(dòng)態(tài)構(gòu)建的類需要在調(diào)用objc_registerClassPair之后才可以被使用囤官,同樣沒(méi)有機(jī)會(huì)再添加成員變量。
因?yàn)榉椒ê蛯傩圆⒉弧皩儆凇鳖悓?shí)例蛤虐,而成員變量“屬于”類實(shí)例党饮。我們所說(shuō)的“類實(shí)例”概念,指的是一塊內(nèi)存區(qū)域驳庭,包含了isa指針和所有的成員變量刑顺。所以假如允許動(dòng)態(tài)修改類成員變量布局,已經(jīng)創(chuàng)建出的類實(shí)例就不符合類定義了饲常,變成了無(wú)效對(duì)象蹲堂。但方法定義是在objc_class中管理的,不管如何增刪類方法贝淤,都不影響類實(shí)例的內(nèi)存布局柒竞,已經(jīng)創(chuàng)建出的類實(shí)例仍然可正常使用。
然而如果在運(yùn)行時(shí)動(dòng)態(tài)生成一個(gè)類播聪,就可以為其添加成員變量和方法, 如下圖所示:
添加的方法必須是已經(jīng)實(shí)現(xiàn)的朽基,所以先手寫(xiě)這個(gè)方法
如上就動(dòng)態(tài)創(chuàng)建了一個(gè)類布隔。下面我們開(kāi)始使用這個(gè)類。
打印結(jié)果如下:
5.objc中向一個(gè)nil對(duì)象發(fā)送消息將會(huì)發(fā)生什么稼虎?(返回值是對(duì)象衅檀,是標(biāo)量,結(jié)構(gòu)體)
objc中向一個(gè)nil對(duì)象發(fā)送消息將會(huì)發(fā)生什么霎俩?
附:
附:
2017年5月iOS招人心得答案總結(jié)(基礎(chǔ)篇)
2017年5月iOS招人心得答案總結(jié)(中級(jí)篇)
2017年5月iOS招人心得答案總結(jié)(高級(jí)篇)
題庫(kù):
2017年5月iOS招人心得(附面試題)