說說你對 OC 中 load 方法和 initialize 方法的異同。——主要說一下執(zhí)行時間,各自用途,沒實現(xiàn)子類的方法會不會調(diào)用父類的?
說說你對 block 的理解。—— 三種 block,棧上的自動復(fù)制到堆上,block 的屬性修飾符是 copy,循環(huán)引用的原理和解決方案。
說說你對 runtime 的理解。——主要是方法調(diào)用時如何查找緩存,如何找到方法,找不到方法時怎么轉(zhuǎn)發(fā),對象的內(nèi)存布局。
提高方法查找機制效率-Class Cache
通過上文我們知道,在OC中,方法是通過isa指針,查找Class中的Method list來查詢的。而一個類往往會實現(xiàn)很多方法,每次調(diào)用都查詢一次Method list的分發(fā)表(dispatch table)的代價是很高的(因為,這種查詢可能每個RunLoop就執(zhí)行上億次)。這也就引入了Class Cache.
Class Cache認為,當一個方法被調(diào)用,那么它之后被調(diào)用的可能性比較大。
舉個例子,我們常見的alloc,init,調(diào)用順序如下
CustomObject * obj = [[CustomObject alloc] init];
alloc是類方法,沿著isa找到CustomObject類元對象,發(fā)現(xiàn)沒有實現(xiàn)alloc
沿著super,找到NSObject類元方法,執(zhí)行alloc方法,并把alloc加入到NSObject類元對象的Class Cache中
init是實例方法,沿著isa找到CustomObject的類對象,發(fā)現(xiàn)沒有實現(xiàn)init
沿著super,找到NSObject類對象,執(zhí)行init,并把init加入到NSObject的類對象Class Cache中
這里,再提一下alloc,init兩個方法
alloc方法的文檔
初始化isa,其他所有屬性被設(shè)為0
init
NSObject的init返回self,其余的子類要調(diào)用[super init]進行必要的初始化工作。
為什么要放在一起寫?
因為alloc和init有可能返回不同的對象
id a = [NSMutableArray alloc];
id b = [a init];
NSLog(@"%p",a);
NSLog(@"%p",b);
輸出
0x7fc550400fb0
0x7fc5505523a0
- 方法的selector
這兩個參數(shù)為方法的實現(xiàn)提供了調(diào)用者的信息。之所以說是隱藏的,是因為它們在定義方法的源代碼中沒有聲明。它們是在編譯期被插入實現(xiàn)代碼的。
雖然這些參數(shù)沒有顯示聲明,但在代碼中仍然可以引用它們。我們可以使用self來引用接收者對象,使用_cmd來引用選擇器。如下代碼所示:
- strange
{
id target = getTheReceiver();
SEL method = getTheMethod();
if ( target == self || method == _cmd )
return nil;
return [target performSelector:method];
}
當然,這兩個參數(shù)我們用得比較多的是self,_cmd在實際中用得比較少。
獲取方法地址
Runtime中方法的動態(tài)綁定讓我們寫代碼時更具靈活性,如我們可以把消息轉(zhuǎn)發(fā)給我們想要的對象,或者隨意交換一個方法的實現(xiàn)等。不過靈活性的提 升也帶來了性能上的一些損耗。畢竟我們需要去查找方法的實現(xiàn),而不像函數(shù)調(diào)用來得那么直接。當然,方法的緩存一定程度上解決了這一問題。
我們上面提到過,如果想要避開這種動態(tài)綁定方式,我們可以獲取方法實現(xiàn)的地址,然后像調(diào)用函數(shù)一樣來直接調(diào)用它。特別是當我們需要在一個循環(huán)內(nèi)頻繁地調(diào)用一個特定的方法時,通過這種方式可以提高程序的性能。
NSObject類提供了methodForSelector:方法,讓我們可以獲取到方法的指針,然后通過這個指針來調(diào)用實現(xiàn)代碼。我們需要將methodForSelector:返回的指針轉(zhuǎn)換為合適的函數(shù)類型,函數(shù)參數(shù)和返回值都需要匹配上。
我們通過以下代碼來看看methodForSelector:的使用:
void (*setter)(id, SEL, BOOL);
int i;
setter = (void (*)(id, SEL, BOOL))[target
methodForSelector:@selector(setFilled:)];
for ( i = 0 ; i < 1000 ; i++ )
setter(targetList[i], @selector(setFilled:), YES);
這里需要注意的就是函數(shù)指針的前兩個參數(shù)必須是id和SEL。
當然這種方式只適合于在類似于for循環(huán)這種情況下頻繁調(diào)用同一方法,以提高性能的情況。另外,methodForSelector:是由Cocoa運行時提供的;它不是Objective-C語言的特性。
消息轉(zhuǎn)發(fā)
當一個對象能接收一個消息時,就會走正常的方法調(diào)用流程。但如果一個對象無法接收指定消息時,又會發(fā)生什么事呢?默認情況下,如果是以 [object message]的方式調(diào)用方法,如果object無法響應(yīng)message消息時,編譯器會報錯。但如果是以perform…的形式來調(diào)用,則需要等到運 行時才能確定object是否能接收message消息。如果不能,則程序崩潰。
通常,當我們不能確定一個對象是否能接收某個消息時,會先調(diào)用respondsToSelector:來判斷一下。如下代碼所示:
if ([self respondsToSelector:@selector(method)]) {
[self performSelector:@selector(method)];
}
不過,我們這邊想討論下不使用respondsToSelector:判斷的情況。這才是我們這一節(jié)的重點。
當一個對象無法接收某一消息時,就會啟動所謂”消息轉(zhuǎn)發(fā)(message forwarding)“機制,通過這一機制,我們可以告訴對象如何處理未知的消息。默認情況下,對象接收到未知的消息,會導(dǎo)致程序崩潰,通過控制臺,我們可以看到以下異常信息:
-[SUTRuntimeMethod method]: unrecognized selector sent to instance 0x100111940
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[SUTRuntimeMethod method]: unrecognized selector sent to instance 0x100111940'
這段異常信息實際上是由NSObject的”doesNotRecognizeSelector”方法拋出的。不過,我們可以采取一些措施,讓我們的程序執(zhí)行特定的邏輯,而避免程序的崩潰。
消息轉(zhuǎn)發(fā)機制基本上分為三個步驟:
- 動態(tài)方法解析
- 備用接收者
- 完整轉(zhuǎn)發(fā)
下面我們詳細討論一下這三個步驟。
動態(tài)方法解析
對象在接收到未知的消息時,首先會調(diào)用所屬類的類方法+resolveInstanceMethod:(實例方法)或 者+resolveClassMethod:(類方法)。在這個方法中,我們有機會為該未知消息新增一個”處理方法”“。不過使用該方法的前提是我們已經(jīng) 實現(xiàn)了該”處理方法”,只需要在運行時通過class_addMethod函數(shù)動態(tài)添加到類里面就可以了。如下代碼所示:
void functionForMethod1(id self, SEL _cmd) {
NSLog(@"%@, %p", self, _cmd);
}
+ (BOOL)resolveInstanceMethod:(SEL)sel {
NSString *selectorString = NSStringFromSelector(sel);
if ([selectorString isEqualToString:@"method1"]) {
class_addMethod(self.class, @selector(method1), (IMP)functionForMethod1, "@:");
}
return [super resolveInstanceMethod:sel];
}
不過這種方案更多的是為了實現(xiàn)@dynamic屬性。
備用接收者
如果在上一步無法處理消息,則Runtime會繼續(xù)調(diào)以下方法:
- (id)forwardingTargetForSelector:(SEL)aSelector
如果一個對象實現(xiàn)了這個方法,并返回一個非nil的結(jié)果,則這個對象會作為消息的新接收者,且消息會被分發(fā)到這個對象。當然這個對象不能是self自身,否則就是出現(xiàn)無限循環(huán)。當然,如果我們沒有指定相應(yīng)的對象來處理aSelector,則應(yīng)該調(diào)用父類的實現(xiàn)來返回結(jié)果。
使用這個方法通常是在對象內(nèi)部,可能還有一系列其它對象能處理該消息,我們便可借這些對象來處理消息并返回,這樣在對象外部看來,還是由該對象親自處理了這一消息。如下代碼所示:
@interface SUTRuntimeMethodHelper : NSObject
- (void)method2;
@end
@implementation SUTRuntimeMethodHelper
- (void)method2 {
NSLog(@"%@, %p", self, _cmd);
}
@end
#pragma mark -
@interface SUTRuntimeMethod () {
SUTRuntimeMethodHelper *_helper;
}
@end
@implementation SUTRuntimeMethod
+ (instancetype)object {
return [[self alloc] init];
}
- (instancetype)init {
self = [super init];
if (self != nil) {
_helper = [[SUTRuntimeMethodHelper alloc] init];
}
return self;
}
- (void)test {
[self performSelector:@selector(method2)];
}
- (id)forwardingTargetForSelector:(SEL)aSelector {
NSLog(@"forwardingTargetForSelector");
NSString *selectorString = NSStringFromSelector(aSelector);
// 將消息轉(zhuǎn)發(fā)給_helper來處理
if ([selectorString isEqualToString:@"method2"]) {
return _helper;
}
return [super forwardingTargetForSelector:aSelector];
}
@end
這一步合適于我們只想將消息轉(zhuǎn)發(fā)到另一個能處理該消息的對象上。但這一步無法對消息進行處理,如操作消息的參數(shù)和返回值。
完整消息轉(zhuǎn)發(fā)
如果在上一步還不能處理未知消息,則唯一能做的就是啟用完整的消息轉(zhuǎn)發(fā)機制了。此時會調(diào)用以下方法:
- (void)forwardInvocation:(NSInvocation *)anInvocation
運行時系統(tǒng)會在這一步給消息接收者最后一次機會將消息轉(zhuǎn)發(fā)給其它對象。對象會創(chuàng)建一個表示消息的NSInvocation對象,把與尚未處理的消息 有關(guān)的全部細節(jié)都封裝在anInvocation中,包括selector,目標(target)和參數(shù)。我們可以在forwardInvocation 方法中選擇將消息轉(zhuǎn)發(fā)給其它對象。
//內(nèi)存布局
http://blog.csdn.net/cx_wzp/article/details/50905708
說說你對 MVC 和 MVVM 的理解。—— MVC 的 C 太臃腫,可以和 V 合并,變成 MVVM 中的 V,而 VM 用來將 M 轉(zhuǎn)化成 V 能用的數(shù)據(jù)。
說說 UITableView 的調(diào)優(yōu)。——一方面是通過 instruments 檢查影響性能的地方,另一方面是估算高度并在 runloop 空閑時緩存。
談?wù)勀銓?ARC 的理解。ARC 是編譯器完成的,依靠引用計數(shù),談?wù)剮讉€屬性修飾符的內(nèi)存管理策略,什么情況下會內(nèi)存泄露
7、層和UIView的區(qū)別是什么?
答:兩者最大的區(qū)別是,圖層不會直接渲染到屏幕上,UIView是iOS系統(tǒng)中界面元素的基礎(chǔ),所有的界面元素都是繼承自它。它本身完全是由CoreAnimation來實現(xiàn)的。它真正的繪圖部分,是由一個CALayer類來管理。UIView本身更像是一個CALayer的管理器。一個UIView上可以有n個CALayer,每個layer顯示一種東西,增強UIView的展現(xiàn)能力。
3、垃圾回收和引用計數(shù)的區(qū)別?引用計數(shù)為0了才釋放
2、自動釋放池的作用?
autorelease的使用
自動釋放池:是用來自動釋放對象的,不需要關(guān)心對象釋放的時間,不需要關(guān)心對象什么時候調(diào)用release
自動釋放池釋放的時間:自動釋放池結(jié)束
自動釋放池原理:當池子結(jié)束,會想池子里面的對象發(fā)送一條release消息
自動釋放池使用:1.創(chuàng)建對象 2.加入自動釋放池
兩種使用方式:
①Person *p = [Person new];
[p autorelease];
②Person *p1 = [[Person new]autorelease];
注意事項:
1.并不是放到自動釋放池中的代碼中,就會自動加入到自動釋放池的
需要我們調(diào)用autorelease方法的
在自動釋放池的外部調(diào)用autorelease方法,是不會被加入到自動釋放池中的
不管這個對象是在自動釋放池內(nèi)部還是外部創(chuàng)建的,只要在這個對象在自動釋放池中調(diào)用autorelease方法,那么就會被放到自動釋放池中
總結(jié):不管是在什么地方創(chuàng)建的對象,都必須在自動釋放池中,調(diào)用autorelease方法,才會被加入自動釋放池中
2.自動釋放池的嵌套使用:自動釋放池是個棧結(jié)構(gòu),先進后出(每個自動釋放池就當成一個桶,先放到下面的,最后拿出來,有利于理解)
延遲調(diào)用release,在自動釋放池結(jié)束時,讓對象調(diào)用release
注意:自動釋放池可不是直接釋放對象,而只是讓對象release一次,如果對象的retainCount為2,那么自動釋放池只能讓retainCount變?yōu)?,對象就銷毀不了
3.自動釋放池中不適合放占用內(nèi)存比較大的對象
1)這是種延遲釋放機制,是直到自動釋放池結(jié)束才釋放的,中間大內(nèi)存文件一直在占用內(nèi)存
2)不要把大量循環(huán)操作放到同一個@autoreleasepool(自動釋放池)之間,這樣會造成內(nèi)存峰值的
4.錯誤用法:
1)連續(xù)調(diào)用多次autorelease,釋放池結(jié)束時會執(zhí)行兩次release
? 注意:一個retainCount為1的對象,如果release兩次,程序是會崩潰的
· 2)alloc之后調(diào)用了autorelease,之后又調(diào)用了release(還是release兩次)
5.autorelease的應(yīng)用場景:
經(jīng)常用來在類方法中,快速創(chuàng)建一個對象
我們平常定義一個指針,先alloc,再init,最后還要手動釋放,太麻煩,索性直接當定義出來的同時,調(diào)用一下autorelease方法,當自動釋放池結(jié)束的時候,自動就release,通常可以用于重寫init的時候,直接放在init里
【小結(jié)】:
1:自動釋放池的數(shù)據(jù)結(jié)構(gòu)
自動釋放池是以棧的形式實現(xiàn),當你創(chuàng)建一個新的自動釋放池,它將會被添加到棧頂。接受autorelease
消息的對象將會唄放入棧頂
2:如何持有對象
當我們使用alloc,copy,retain對象獲取一個對象時,我們需要負責顯示的安排對象的銷毀,其他方法獲取的
的對象將交給自動釋放池進行釋放(單例模式除外)
3:release和drain的區(qū)別
當我們向自動釋放池pool發(fā)送release消息,將會向池中臨時對象發(fā)送一條release消息,并且自身也會唄銷毀。
向它發(fā)送drain消息時,只會指定前者。
1.Objective-C可以實現(xiàn)多繼承嗎?可以實現(xiàn)多個接口嗎?Category是什么?重寫一個類的方式是用繼承好還是用分類好?為什么?
2.OC使用協(xié)議實現(xiàn)多繼承,可以遵守多個協(xié)議實現(xiàn)多接口。category是OC中的類別,類別是用于給一個現(xiàn)有類添加新方法。重寫類一般采用繼承的方式,分類(類別)在給以個類添加同名方法后,會造成原有類中方法的實效,而繼承重寫的方法,依然可以在使用父類對象調(diào)用該方法。
3.定義屬性的時候,什么時候使用retain/copy/assign?寫一個setter方法,用于完成@property(nonatomic,retain) NSString* name;寫一個setter方法,用于完成@property(nonatomic,copy)NSString* name;
retain用于保留對象的引用計數(shù),在使用retain聲明的屬性做賦值的時候,成員變量指針會保留被賦值對象的引用計數(shù)。
copy聲明的屬性,在使用屬性賦值的時候會,成員指針會指向新副本,這個副本是一個不可變副本,不論賦值對象是不是可變的。
assign用于基本數(shù)據(jù)類型的屬性聲明,不涉及到內(nèi)存管理的問題,也是缺省參數(shù)
retain聲明的屬性的setter方法展開
- (void)setName:(NSString*)name
{
if(_name != name)
{
[_namerelease];
_name= [name retain];
}
}
copy聲明的屬性的setter方法展開
- (void)setName:(NSString*)name
{
if(_name != name)
{
[_namerelease];
_name= [name copy];
}
}
4.什么時候使用NSMutableArray/什么時候使用NSArray
NSMutableArray一般在需要隨時更改數(shù)組結(jié)構(gòu)的時候使用
NSArray一般用于保存一些不需要修改邏輯的數(shù)據(jù)
5.實現(xiàn)字符串“I LOVE CHINA”反串成“CHINA LOVE I”
- pch文件的作用
.pch表示"precompiled header",這是一個你工程要用到的來自于外部框架的頭文件列表。xcode將編譯這些頭到文件,這將減少你在選擇Build或Build and Go時編譯項目的時間。通常用到的頭文件已經(jīng)自動包含了pch,系統(tǒng)編譯每個cpp文件前,都會先include這個文件。這樣就節(jié)省了添加include的時間,相當于加速編譯
還有就是可以再這里面放入宏,在整個工程中都可以用
7.怎樣解決重復(fù)編譯
ifndef _DEBUG
ifdef USE_MYLIB
................
endif
- awakeFromNib與viewDidLoad區(qū)別
awakeFromNib
當.nib文件被加載的時候,會發(fā)送一個awakeFromNib的消息到.nib文件中的每個對象,每個對象都可以定義自己的awakeFromNib函數(shù)來響應(yīng)這個消息,執(zhí)行一些必要的操作。也就是說通過nib文件創(chuàng)建view對象是執(zhí)行awakeFromNib。
viewDidLoad
當view對象被加載到內(nèi)存是就會執(zhí)行viewDidLoad,所以不管通過nib文件還是代碼的方式創(chuàng)建對象都會執(zhí)行viewDidLoad。 - LayoutSubviews何時會被調(diào)用
當要調(diào)整subViews時候,需要重寫layoutSubviews方法。
1:初始化init方法時候不會觸發(fā)。
2:滾動UIScrollView時會觸發(fā)
3:旋轉(zhuǎn)UIScreen時會觸發(fā)
4:當改變view的值時候會觸發(fā),前提是frame前后值發(fā)生了變化
5:當改變UIview的大小時候會觸發(fā) - public/private/protected的具體區(qū)別
public公共,加上這個修飾的類或?qū)傩裕梢栽谕粋€包或者別的包里面訪問
private私有的,加上這個修飾的類或?qū)傩裕荒茉谕惱镌L問,同包和別的包不能訪問
protected保護,加上這個修飾的類或?qū)傩裕荒茉陬惡屯L問,別的包不能訪問 - ARC是什么
ARC是iOS 5推出的新功能,全稱叫ARC(Automatic Reference Counting)。簡單地說,就是代碼中自動加入了retain/release,原先需要手動添加的用來處理內(nèi)存管理的引用計數(shù)的代碼可以自動地由編譯器完成了。
該機能在iOS 5/ Mac OS X 10.7開始導(dǎo)入,利用Xcode4.2可以使用該機能。簡單地理解ARC,就是通過指定的語法,讓編譯器(LLVM
3.0)在編譯代碼時,自動生成實例的引用計數(shù)管理部分代碼。有一點,ARC并不是GC,它只是一種代碼靜態(tài)分析(Static
Analyzer)工具。
12.寫一個“標準”宏,這個宏輸入兩個參數(shù)并返回較小的
define MIN(X,Y)((X)>(Y)?(Y):(X))
13.Objective-c中有多重繼承么?不是的話有聲明替代方式?
沒有多繼承,可以通過協(xié)議模擬多繼承
14.Objective-c中有私有方法嗎?私有變量呢?
沒有私有方法,但可以將方法直接實現(xiàn)在.m文件中不在.h文件中聲明時,外部也不能訪問。
有私有變量
15.iPhone OS中有沒有垃圾回收?
沒有
16.常見的object-c的數(shù)據(jù)類型有哪些,和c的基本類型有什么區(qū)別
答:常見的object-c的數(shù)據(jù)類型有NSInteger、CGFloat、NSString、NSNumber、NSArray、NSData,NSInteger會根據(jù)系統(tǒng)是32位還是64位來決定是本身是int還是Long,
CGFloat會根據(jù)系統(tǒng)是32位還是64位來決定是本身是float還是double,NSString、NSNumber、NSArray、NSData都是指針類型的對象,在堆中分配空間,而c語言中的char,[]等都是在棧中分配空間
17.id聲明的對象有什么特性?
id聲明的對象具有運行時的特性,即可以指向任意類型的objcetive-c的對象;
18.想nil對象發(fā)送消息會發(fā)生什么?
答:在Objective-C中向nil發(fā)送消息是完全有效的,只是在運行時不會有任何作用。
19.什么是block?block實現(xiàn)原理?
答:block是一個特殊的OC對象,它建立在棧上,而不是堆上,這么做一個是為性能考慮,還有就是方便訪問局部變量。默認情況下block使用到的局部變量都會被復(fù)制,而不是保留。所以它無法改變局部變量的值。如果在變量面前加上__block,那么編譯器回去不會復(fù)制變量,而是去找變量的地址,通過地址來訪問變量,實際上就是直接操作變量。另外block是在棧上分配的,所以一旦離開作用域,就會釋放,因此如果你要把快用在別的地方,必須要復(fù)制一份。block是不能保留的,
retain對塊沒有意義。
20.C++和OC,JAVA和OC之間的區(qū)別?
C++是功能強大,豐富的面向?qū)ο缶幊陶Z言,具有私有、公有、保護權(quán)限的三種成員變量和成員方法,具有私有、公有、保護三種繼承方式,具有重寫,重載,虛函數(shù),虛基類等多態(tài)方式,通過虛基類實現(xiàn)代理回調(diào)。自定義類可以沒有父類。另外具備向量,模板,友元,重載運算符等多種獨特語法
Obj-C是針對mac OS和iOS設(shè)備應(yīng)用程序開發(fā)的專屬編程語言,采用動態(tài)繼承,消息方法機制,沒有真正的重寫機制,沒有私有方法,繼承方式為公有,具備協(xié)議,類別,Block等獨有的語法,萬用父類為NSObject
JAVA是老牌的面向?qū)ο笳Z言,編寫的程序在JAVA虛擬機上運行,真正實現(xiàn)了一次編譯到處運行,具有復(fù)雜的內(nèi)存回收機制,單繼承模式,接口語法類似Obj-C的協(xié)議
21.抽象與接口的區(qū)別?
聲明方法的存在而不去實現(xiàn)它的類被叫做抽象類(abstract class),它用于要創(chuàng)建一個體現(xiàn)某些基本行為的類,并為該類聲明方法,但不能在該類中實現(xiàn)該類的情況。不能創(chuàng)建abstract類的實例。然而可以創(chuàng)建一個變量,其類型是一個抽象類,并讓它指向具體子類的一個實例。不能有抽象構(gòu)造函數(shù)或抽象靜態(tài)方法。Abstract類的子類為它們父類中的所有抽象方法提供實現(xiàn),否則它們也是抽象類為。取而代之,在子類中實現(xiàn)該方法。知道其行為的其它類可以在類中實現(xiàn)這些方法。
接口(interface)是抽象類的變體。在接口中,所有方法都是抽象的。多繼承性可通過實現(xiàn)這樣的接口而獲得。接口中的所有方法都是抽象的,沒有一個有程序體。接口只可以定義static
final成員變量。接口的實現(xiàn)與子類相似,除了該實現(xiàn)類不能從接口定義中繼承行為。當類實現(xiàn)特殊接口時,它定義(即將程序體給予)所有這種接口的方法。然后,它可以在實現(xiàn)了該接口的類的任何對象上調(diào)用接口的方法。由于有抽象類,它允許使用接口名作為引用變量的類型。通常的動態(tài)聯(lián)編將生效。引用可以轉(zhuǎn)換到接口類型或從接口類型轉(zhuǎn)換,instanceof運算符可以用來決定某對象的類是否實現(xiàn)了接口。
22.nil與NULL的區(qū)別?
從Objective-C語言的官方說法上看,nil表示指向?qū)ο蟮闹羔樇此^對象的引用為空,NULL表示指向基礎(chǔ)類型變量即C語言變量的指針為空。如果在非ARC程序的編寫過程中,兩個空是可以互換的,但是在ARC環(huán)境下,普通指針和對象引用被嚴格限制,不能交換使用,因此也應(yīng)盡量不互換使用nil與NULL
- BOOL與bool的區(qū)別?
bool是C語言C99標準中增添的變量類型,Object-C僅僅是從C語言繼承了這種類型,該類型有true和false兩個值,表示真和假。BOOL是Obj-C獨有的布爾類型,有YES和NO兩個值,分別是1和0的宏。Obj-C中同時認為所有非0的值都是真值,0為假值
24.OC如何實現(xiàn)私有方法?
Obj-C語法中并沒有私有方法的概念,但是由于Obj-C是通過導(dǎo)入其他類的頭文件來獲取其他類所擁有的成員方法的聲明,因此可以采用編寫方法時,不聲明,或僅在.m文件中的匿名類別中聲明的方式,使方法對外不可見,即可達到方法私有化的目的。但是外部類仍然可以通過@selector來訪問確實存在的私有方法,因此嚴格來講Obj-C確實不能真正實現(xiàn)方法私有化
25.#import和#include的區(qū)別@ class代表什么
預(yù)編譯指令
Objective-C:#import
C,C++:#include
import由gcc編譯器支持
在Objective-C中,#import被當成#include指令的改良版本來使用。除此之外,#import確定一個文件只能被導(dǎo)入一次,這使你在遞歸包含中不會出現(xiàn)問題。
使用哪一個還是由你來決定。一般來說,在導(dǎo)入Objective-C頭文件的時候使用#import,包含C頭文件時使用#include。比如:
import
include
include
import比起#include的好處就是不會引起交叉編譯
二、@class是用來做類引用的
@class就是告訴編譯器有這么一個類,至于類的定義是啥不知道
@class一般用于頭文件中需要聲明該類的某個實例變量的時候用到,在m文件中還是需要使用#import
- NSString和NSMutableString的區(qū)別
NSString是一個不可變的字符串對象。這不是表示這個對象聲明的變量的值不可變,而是表示它初始化以后,你不能改變該變量所分配的內(nèi)存中的值,但你可以重新分配該變量所處的內(nèi)存空間。而NSMutableString是可變的,意味著你可以追加它的內(nèi)存空間,或者修改它所分配的內(nèi)存空間中的值。
27..關(guān)于語句NSString * str= [NSData alloc]init,編譯和運行分別str代表什么對象?
首先,聲明NSString str是告訴編譯器,str是一個指向某個Objective-C對象的指針。因為不管指向的是什么類型的對象,一個指針所占的內(nèi)存空間都是固定的,所以這里聲明成任何類型的對象,最終生成的可執(zhí)行代碼都是沒有區(qū)別的。這里限定了NSString只不過是告訴編譯器,請把str當做一個NSString來檢查,如果后面調(diào)用了非NSString的方法,會產(chǎn)生警告。
接著,你創(chuàng)建了一個NSData對象,然后把這個對象所在的內(nèi)存地址保存在str里。那么運行時,str指向的內(nèi)存空間就是一個NSData對象。你可以把str當做一個NSData對象來用。
28.socket通信的幾個關(guān)鍵步驟
面向連接的socket通信就像與對方打電話,首先需要通過電話建立一個連接,連接建立好之后,彼此才能雙向通信。它有幾個關(guān)鍵步驟
服務(wù)器端通常以守護進程的方式實現(xiàn):
1:創(chuàng)建守護進程
2:獲取或注冊服務(wù)
3:創(chuàng)建socket并綁定地址
4:開始監(jiān)聽
5:接收客戶端連接請求
6:進行數(shù)據(jù)傳輸
客戶端
1:獲取或注冊服務(wù)
2:創(chuàng)建socket
3:發(fā)送連接請求
29.類別意義?與繼承的區(qū)別
當我們添加頭文件以后,對已知的類,會自動提示你對這個類添加的方法
主要用途,對于原生不會造成破壞,使用原生就可以提示出你的方法
30.Core Foundation中提供了哪幾種操作Socket的方法?
CFNetwork、CFSocket和BSDSocket
31.用id聲明的對象有什么特性?
?沒有號
?動態(tài)數(shù)據(jù)類型
?可以指向任何類的對象(設(shè)置是nil),而不關(guān)心其具體類型
?在運行時檢查其具體類型
?可以對其發(fā)送任何(存在的)消息
32,self.name=“object”name=“object”有什么區(qū)別?
前者實際上是調(diào)用了set方法給變量賦值而后者是直接給變量賦值
33.shell中,將command1的輸出作為command2的輸出應(yīng)該使用的命令是?
重定向命令>
command1>command2
34.下面的數(shù)據(jù)結(jié)構(gòu)中不屬于線性結(jié)構(gòu)的是:棧,鏈表,二叉樹,線性表
線性結(jié)構(gòu):棧,鏈表,線性表
非線性結(jié)構(gòu):二叉樹
35,oc中有沒有多繼承,如果沒有用什么方法替代?
沒有用協(xié)議代替多繼承
36.常見的Objective-C的數(shù)據(jù)類型有哪些,和C的基本數(shù)據(jù)類型有什么區(qū)別
OC中常用數(shù)據(jù)類型有NSArray,NSDictionary,NSData,NSString,NSMutbleString等等,和C的最大區(qū)別為OC中的類型是類類型,需要實例化對象才能用。C中是一般數(shù)據(jù)類型直接操作內(nèi)存空間
37.self.name=@“aa”和_name=@“aa”的區(qū)別
答:self.name=@“aa”是通過set方法進行賦值,_name=@“aa”是直接復(fù)制給成員變量
38.C語言中指針與數(shù)組的區(qū)別
答:指針是變量可以修改指向的方向,數(shù)組名是地址常量,不能被修改
39.new delete malloc free的含義
c++:new申請內(nèi)存,delete釋放掉指針指向的內(nèi)存
c:malloc動態(tài)申請內(nèi)存,free釋放指針指向的內(nèi)存
40.常引用什么時候使用
如果既要利用引用提高程序的效率,又要保護傳遞給函數(shù)的數(shù)據(jù)不在函數(shù)中被改變,就要使用常引用
41.c/oc/c++有什么區(qū)別和聯(lián)系
C相對于C++和OC而言更偏重于邏輯算法,這是因為C是面向過程,C++和OC都是面向?qū)ο蟆和C++的聯(lián)系:C是C++的一個自洽子集,C++是C的超集,OC是C的擴展,C++和OC基本兼容C的語法。
42.const的用法
const修飾變量表示該變量是只讀變量(有些人管它叫常量),即只能引用而不能修改
constint p;表示指針變量P指向的數(shù)據(jù)不能改
intconst p;表示指針變量P的值不能該,或者說是指針P的指向不能改
43.[pool release]和[pool drain]有什么區(qū)別
drain和release都會促使自動釋放池對象向池內(nèi)的每一個對象發(fā)送release消息來釋放池內(nèi)對象的引用計數(shù),但是release觸發(fā)的這個操作,不會考慮對象是否需要release,而drain會在自動釋放池向池內(nèi)對象發(fā)送release消息的時候,考慮對象是否需要release
44.自動釋放池和GC一樣嗎,iphone有沒有GC
在引用計數(shù)環(huán)境下,
ios是沒有垃圾回收的,自動釋放池是oc中管理內(nèi)存的一種方式,它和gc是本質(zhì)區(qū)別的,自動釋放池管理內(nèi)存的前提是,必須把要管理內(nèi)存的對象加入池內(nèi),才會生效。而gc是不斷檢測當前程序中是否有不再使用的內(nèi)存進而釋放。
45.當A類 中的某個方法執(zhí)行到某處時,這時想在B類中執(zhí)行某個方法,如何做?并做簡單說明
用代理執(zhí)行代理方法
說明:在b類中實現(xiàn)協(xié)議方法,設(shè)置a的代理為b,在指定方法內(nèi)調(diào)用代理的協(xié)議方法
46.類別的作用?
答案:category可以在不獲悉,不改變原來代碼的情況下往里面添加新的方法,只能添加,不能刪除修改。
并且如果類別和原來類中的方法產(chǎn)生名稱沖突,則類別將覆蓋原來的方法,因為類別具有更高的優(yōu)先級。
類別主要有3個作用:
(1)將類的實現(xiàn)分散到多個不同文件或多個不同框架中。
(2)創(chuàng)建對私有方法的前向引用。
(3)向?qū)ο筇砑臃钦絽f(xié)議。
47.簡述extern
C的作用
可以在C++中使用C的已編譯好的函數(shù)模塊,在c++中么用到c語言寫的函數(shù),聲明一下,在DLL中經(jīng)常看到,避免C++
name mangling,主要用于動態(tài)鏈接庫,使得導(dǎo)出函數(shù)名稱與C語言規(guī)則一致(不改變),方便不同的編譯器甚至是不同的開發(fā)語言調(diào)用。
extern
"C"是告訴C++編譯器以C Linkage方式編譯,也就是抑制C++的name
mangling機制。
編程:
1.寫出@proerty(nonatomic,retain)Person
*person;@synthesize person具體實現(xiàn)。
- (void)setPerson:(Person *)person
{
if(_person !=person){
[_personrelease];
[_person =person retain];
}
}
- (Person *)person {
return _person;
}
2.從普通id類型對象轉(zhuǎn)換成數(shù)字對象,因為配置了限定詞.1f,所以結(jié)果四舍五入,并保留一位小數(shù)
NSDictionary* rowData =[NSDictionarydictionaryWithObjectsAndKeys:@"46.95",@"price",nil];
NSLog(@"a double value:%.1f",[(NSNumber*)[rowDataobjectForKey:@"price"] doubleValue]);
輸出:
a double value:47.0
3,寫一個委托的interface
#import
@protocolMyDelegate;//聲明
@interfaceMyClass:NSobject
{
iddelegate;
}
@end
@protocolMyDelegate//委托方法
-(void)selector:(NSString *)args;
@end
4:請看下面一段代碼
staticint a=1;
intmain(){
intb=2;
char*c=NUll;
c=(char*)malloc(100*sizeof(char));
return0;
}
問:1,訪問abc三者的效率從高到低依次是:
bca
2,在最壞情況下排序速度最快的是:歸并排序
復(fù)雜度最高的是:快排
a,快排,冒泡,堆,歸并
5.看下面的程序
=========================================
NSMutableArray *arr = [[NSMutableArrayarray] retain];
NSString *str = [NSStringstringWithFormat:@"test"];
[str retain];
[arr addObject:str];
NSLog(@"%@%lu",str,[strretainCount]);
[str retain];
[str release];
[str release];
NSLog(@"%@%lu",str,[strretainCount]);
[arr removeObject:str];
NSLog(@"%@%lu",str,[strretainCount]);
==================================================
三次打印的retainCount分別是什么,為什么?
答:
分別是3,2,1,
初始化的時候的為1,retain的時候+1,往數(shù)組里add的時候+1,release的時候-1,從數(shù)組里移除的時候-1