iOS程序員面試分類模擬29_第1頁
iOS程序員面試分類模擬29_第2頁
iOS程序員面試分類模擬29_第3頁
iOS程序員面試分類模擬29_第4頁
iOS程序員面試分類模擬29_第5頁
已閱讀5頁,還剩18頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

iOS程序員面試分類模擬29簡答題1.

如何使用runtime動(dòng)態(tài)添加一個(gè)類?正確答案:runtime之所以非常強(qiáng)大,很關(guān)鍵的一點(diǎn)就是它能夠動(dòng)態(tài)地創(chuàng)建一個(gè)全新的類或?qū)ο?。在runtime.h文件中(江南博哥)可以查到動(dòng)態(tài)創(chuàng)建一個(gè)類所涉及的所有函數(shù)。

/*創(chuàng)建一個(gè)新類或元類*/

objc_allocateClassPair(Classsuperclass,constchar*name,size_textraBytes)

/*注冊一個(gè)通過objc_allocateClassPair方法創(chuàng)建的類*/

objc_registerClassPair(Classcls)

/*銷毀一個(gè)類及其元類*/

objc_disposeClassPair(Classcls)

上面3個(gè)函數(shù)的作用見表。動(dòng)態(tài)創(chuàng)建類所涉及的3個(gè)函數(shù)函數(shù)名作用objc_allocateClassPair函數(shù)它的作用是創(chuàng)建一個(gè)新類或元類。如果開發(fā)者想讓這個(gè)類成為基類,那么參數(shù)superclass指定為nil。參數(shù)extraBytes是分配給類和元類對象尾部的索引ivars的字節(jié)數(shù),通常指定為0objc_registerClassPair函數(shù)當(dāng)創(chuàng)建完新類后,需要調(diào)用這個(gè)方法來注冊這個(gè)類,之后這個(gè)類才可以在程序中使用objc_disposeClassPair函數(shù)用于銷毀一個(gè)類及其元類。需要注意的一點(diǎn)是,如果程序運(yùn)行中還存在類或其子類的實(shí)例,那么就不能調(diào)用該方法

那么,如何運(yùn)用上述3個(gè)函數(shù)動(dòng)態(tài)地添加一個(gè)類呢?示例代碼如下:

/*創(chuàng)建一個(gè)新類myClass*/

ClassmyClass=objc_allocateClassPair([NSObjectclass],"myClass",0);

/*添加ivar*/

//@encode(aType):返回該類型的C字符串

class_addIvar(myClass,"_address",sizeof(NSString*),log2(sizeof(NSString*)),@encode(NSString*));

class_addIvar(myClass,"_age",sizeof(NSUInteger),log2(sizeof(NSUInteger)),@encode(NSUInteger));

/*注冊類*/

objc_registerClassPair(myClass);

/*創(chuàng)建實(shí)例*/

idobject=[[myClassalloc]init];

/*為ivar設(shè)置值*/

[objectsetValue:@"china"forKey:@"address"];

[objectsetValue:@20forKey:@"age"];

NSLog(@"address=%@,age=%@",[objectvalueForKey:@"address"],[objectvalueForKey:@"age"]);

/*當(dāng)類或者它的子類的實(shí)例還存在,則不能調(diào)用objc_disposeClassPair方法*/

object=nil;

/*銷毀*/

objc_disposeClassPair(myClass);

程序的打印結(jié)果如下:

2016-11-0219:32:39.61501[67782:2681508]address=china,age=20

這樣就通過運(yùn)行時(shí)動(dòng)態(tài)創(chuàng)建了一個(gè)繼承自NSObject的myClass類,并為這個(gè)新類添加了address和age兩個(gè)成員變量。特別需要注意的是,添加成員變量的方法class_addIva必須要在objc_allocateClassPair和objc_registerClassPair之間調(diào)用才行,這里涉及Objective-C中類的成員變量的偏移量,如果在類注冊之后再調(diào)用class_addIva方法,那么會(huì)破壞原來類成員變量正確的偏移量,導(dǎo)致的后果就是會(huì)獲取到錯(cuò)誤的成員變量。

2.

一二三四范式有什么區(qū)別?正確答案:在設(shè)計(jì)與操作維護(hù)數(shù)據(jù)庫時(shí),最關(guān)鍵的問題就是要確保數(shù)據(jù)正確地分布到數(shù)據(jù)庫的表中。使用正確的數(shù)據(jù)結(jié)構(gòu),不僅有助于對數(shù)據(jù)庫進(jìn)行相應(yīng)的存取操作,還可以極大地簡化應(yīng)用程序的其他內(nèi)容(查詢、窗體、報(bào)表、代碼等),正確地進(jìn)行表的設(shè)計(jì)成為“數(shù)據(jù)庫規(guī)范化”,它的目的就是減少數(shù)據(jù)庫中的數(shù)據(jù)冗余,從而增加數(shù)據(jù)的一致性。

規(guī)范化是在識(shí)別數(shù)據(jù)庫中的數(shù)據(jù)元素、關(guān)系,以及定義所需的表和各表中的項(xiàng)目這些初始工作之后的一個(gè)細(xì)化的過程。常見的范式有1NF、2NF、3NF、BCNF及4NF。

1NF,第一范式。它指數(shù)據(jù)庫表的每一列都是不可分割的基本數(shù)據(jù)項(xiàng),同一列中不能有多個(gè)值,即實(shí)體中的某個(gè)屬性不能有多個(gè)值或者不能有重復(fù)的屬性。如果出現(xiàn)重復(fù)的屬性,那么就可能需要定義一個(gè)新的實(shí)體,新的實(shí)體由重復(fù)的屬性構(gòu)成,新實(shí)體與原實(shí)體之間為一對多關(guān)系。第一范式的模式要求屬性值不可再分裂成更小部分,即屬性項(xiàng)不能是屬性組合或由組屬性組成。簡而言之,第一范式就是無重復(fù)的列。例如,由“職工號”“姓名”“電話號碼”組成的表(一個(gè)人可能有一個(gè)辦公電話和一個(gè)移動(dòng)電話),這時(shí)將其規(guī)范化為1NF可以將電話號碼分為“辦公電話”和“移動(dòng)電話”兩個(gè)屬性,即職工(職工號、姓名、辦公電話、移動(dòng)電話)。

2NF,第二范式。第二范式是在第一范式的基礎(chǔ)上建立起來的,即滿足第二范式必須先滿足第一范式。第二范式要求數(shù)據(jù)庫表中的每個(gè)實(shí)例或行必須可以被唯一地區(qū)分。為實(shí)現(xiàn)區(qū)分通常需要為表加上一個(gè)列,以存儲(chǔ)各個(gè)實(shí)例的唯一標(biāo)識(shí)。如果關(guān)系模式(R)為第一范式,并且R中每一個(gè)非主屬性完全函數(shù)依賴于R的某個(gè)候選鍵,則稱R為第二范式模式。(如果A是R的候選鍵的一個(gè)屬性,則稱A是R的主屬性,否則稱A是R的非主屬性。)例如,在選課關(guān)系表(學(xué)號、課程號、成績、學(xué)分),關(guān)鍵字為組合關(guān)鍵字(學(xué)號、課程號),由于非主屬性學(xué)分僅依賴于課程號,對關(guān)鍵字(學(xué)號、課程號)只是部分依賴,而不是完全依賴,所以此種方式導(dǎo)致數(shù)據(jù)冗余及更新異常等問題,解決辦法是將其分為兩個(gè)關(guān)系模式:學(xué)生表(學(xué)號、課程號、分?jǐn)?shù))和課程表(課程號、學(xué)分),新關(guān)系通過學(xué)生表中的外關(guān)鍵字課程號聯(lián)系,在需要時(shí)進(jìn)行連接。

3NF,第三范式。如果R是第二范式,且每個(gè)非主屬性都不傳遞依賴于R的候選鍵,則稱R是第三范式的模式。例如學(xué)生表(學(xué)號、姓名、課程號、成績),其中學(xué)生姓名無重名,所以該表有兩個(gè)候選鍵(學(xué)號、課程號)和(姓名、課程號),則存在函數(shù)依賴:學(xué)號→姓名,(學(xué)號、課程號)→成績,(姓名、課程號)→成績,唯一的非主屬性成績對候選鍵不存在部分依賴,也不存在傳遞依賴,所以屬于第三范式。

BCNF。它構(gòu)建在第三范式的基礎(chǔ)上,如果R是第一范式,且每個(gè)屬性都不傳遞依賴于R的候選鍵,那么稱R為BCNF的模式。假設(shè)倉庫管理關(guān)系表(倉庫號、存儲(chǔ)物品號、管理員號、數(shù)量),滿足一個(gè)管理員只在一個(gè)倉庫工作;一個(gè)倉庫可以存儲(chǔ)多種物品。則存在如下關(guān)系:

(倉庫號、存儲(chǔ)物品號)→(管理員號、數(shù)量)

(管理員號、存儲(chǔ)物品號)→(倉庫號、數(shù)量)

所以,(倉庫號、存儲(chǔ)物品號)和(管理員號、存儲(chǔ)物品號)都是倉庫管理關(guān)系表的候選鍵,表中的唯一非關(guān)鍵字段為數(shù)量,它是符合第三范式的。但是,由于存在如下決定關(guān)系:

(倉庫號)→(管理員號)

(管理員號)→(倉庫號)

即存在關(guān)鍵字段決定關(guān)鍵字段的情況,所以其不符合BCNF范式。把倉庫管理關(guān)系表分解為兩個(gè)關(guān)系表:倉庫管理表(倉庫號、管理員號)和倉庫表(倉庫號、存儲(chǔ)物品號、數(shù)量),這樣的數(shù)據(jù)庫表是符合BCNF范式的,消除了刪除異常、插入異常和更新異常。

4NF,第四范式。設(shè)R是一個(gè)關(guān)系模式,D是R上的多值依賴集合。如果D中成立非平凡多值依賴X→Y時(shí),X必是R的超鍵,那么稱R是第四范式的模式。例如,職工表(職工編號、職工孩子姓名、職工選修課程),在這個(gè)表中同一個(gè)職工也可能會(huì)有多個(gè)職工孩子姓名,同樣,同一個(gè)職工也可能會(huì)有多個(gè)職工選修課程,即這里存在著多值事實(shí),不符合第四范式。如果要符合第四范式,那么只需要將上表分為兩個(gè)表,使它們只有一個(gè)多值事實(shí),例如職工表一(職工編號、職工孩子姓名),職工表二(職工編號、職工選修課程),兩個(gè)表都只有一個(gè)多值事實(shí),所以符合第四范式。

下圖為各范式關(guān)系圖。

各范式關(guān)系圖

3.

為什么iOS中提供UIView和CALayer這兩個(gè)平行的層級結(jié)構(gòu)呢?正確答案:iOS中提供UIView和CALayer這兩個(gè)平行層級結(jié)構(gòu)主要是為了做到職責(zé)分離,實(shí)現(xiàn)視圖的繪制、顯示和布局解耦,避免很多重復(fù)的代碼。在iOS和MacOS兩個(gè)平臺(tái)上,事件和用戶交互有很多地方并不相同,畢竟基于多點(diǎn)觸控的用戶界面和基于鼠標(biāo)鍵盤有著本質(zhì)的區(qū)別,這就是為什么iOS有UIKit和UIView,但是MacOS有Appkit和NSView的原因。它們功能雖然相似,但是在實(shí)現(xiàn)上有著顯著的區(qū)別。創(chuàng)建兩個(gè)層次結(jié)構(gòu)就能夠在iOS與MacOS之間共享代碼,從而使得開發(fā)更加便捷。

4.

contentsScale屬性有什么作用?正確答案:圖層的contentsScale屬性屬于支持高分辨率屏幕(如Retina屏幕)機(jī)制的一部分,它定義了圖層content中圖像的像素尺寸與視圖大小的比例。它也被用來判斷在繪制圖層時(shí)允許為content屬性創(chuàng)建的空間大小,以及需要顯示的圖片的拉伸度。

默認(rèn)情況下,contentsScale的值是1.0,也就是說圖層的繪制系統(tǒng)將會(huì)以每個(gè)點(diǎn)對應(yīng)一個(gè)像素來繪制圖片。如果將其設(shè)置為2.0,那么會(huì)以每個(gè)點(diǎn)對應(yīng)兩個(gè)像素來繪制圖片,此即所謂的Retina屏幕。

在開發(fā)中,有時(shí)會(huì)直接為圖層的content設(shè)置圖片,這時(shí)可以設(shè)置contentsScale為合適的值,以防止圖片在Retina屏幕上顯示不正確(像素化或模糊),代碼如下:

layer.contentsScale=[UIScreenmainScreen].scale;

5.

分別寫一個(gè)setter方法用于完成非ARC下的@property(nonatomic,retain)NSString*name和@property(nonatomic,copy)NSString*name。正確答案:第一種情況,retain是指針變量name對新賦值對象的強(qiáng)引用,相當(dāng)于ARC下的strong,因此對name指針變量set新值時(shí)要先將新賦值對象的引用計(jì)數(shù)加1,然后將指針變量指向新賦值對象,類似于“淺拷貝”。

首先在實(shí)現(xiàn)文件中合成屬性變量:@synthesiszename;,然后兩種情況下自定義setter方法如下,自定義了setter方法后編譯器就不會(huì)再在編譯期重復(fù)合成setter方法了。

/*retain*/

-(void)setName:(NSString*)newName{

if(name!=newName){

[newNameretain];

//新對象引用計(jì)數(shù)加1

[namerelease];

//將指針變量原來的對象釋放掉

name=newName;

//指針變量指向新對象

}

}

第二種情況,copy指當(dāng)對指針變量name賦值新對象時(shí),是將新對象完全copy一份,將copy好的對象復(fù)制給指針變量,即指針指向的是臨時(shí)copy出來的對象,而不是新賦值的那個(gè)對象,因此新賦值對象不需要引用計(jì)數(shù)加1,因?yàn)橹羔樧兞坎]有指向持有它,類似于“深拷貝”。

/*copy*/

-(void)setName:(NSString*)newName{

if(name!=newName){

idtemp=[newNamecopy];

//將新對象原樣克隆一份

[namerelease];

//將指針變量原來的對象釋放掉

name=temp;

//指針變量指向新對象的克隆體

}

}

6.

如何使用NSURLSession進(jìn)行網(wǎng)絡(luò)請求?正確答案:在2013年的WWDC上,蘋果公司推出了NSURLConnection的替代方案:NSURLSession。和NSURLConnection一樣,NSURLSession指的也不僅是同名類NSURLSession,它還包括一系列相關(guān)聯(lián)的類。NSURLSession包括了與之前相同的組件:NSURLRequest與NSURLCache,但是將NSURLConnection替換成了NSURLSession、NSURLSessionConfiguration及NSURLSessionTask的3個(gè)子類:NSURLSessionDataTask、NSURLSessionUploadTask、NSURLSessionDownloadTask。

與NSURLConnection相比,NSURLSession最直接的改進(jìn)就是可以配置每個(gè)session的緩存、協(xié)議、cookie,以及證書策略(CredentialPolicy),甚至跨進(jìn)程共享這些信息。這將允許程序和網(wǎng)絡(luò)基礎(chǔ)框架之間相互獨(dú)立,不會(huì)發(fā)生干擾。每個(gè)NSURLSession對象都由一個(gè)NSURLSessionConfiguration對象進(jìn)行初始化,后者指定了剛才提到的那些策略以及一些用來增強(qiáng)移動(dòng)設(shè)備上性能的新選項(xiàng)。

NSURLSessionTask負(fù)責(zé)處理數(shù)據(jù)的加載以及文件的數(shù)據(jù)在客戶端與服務(wù)器之間的上傳和下載。它是一個(gè)抽象類,一般使用其子類:NSURLSessionDataTask、NSURLSessionUploadTask、NSURLSessionDownloadTask。這3個(gè)子類封裝了現(xiàn)代程序3個(gè)最基本的網(wǎng)絡(luò)任務(wù):獲取數(shù)據(jù)(如JSON或者XML),上傳文件和下載文件。

NSURLSession相關(guān)類的關(guān)系如圖所示。

NSURLSession相關(guān)類的關(guān)系

如何使用NSURLSession像NSURLConnection那樣發(fā)送一個(gè)請求呢?基本步驟如下:

1)創(chuàng)建NSURLSessionConfiguration對象對NSURLSession進(jìn)行配置。

2)創(chuàng)建NSURLSession對象。

3)利用上一步創(chuàng)建好的NSURLSession對象創(chuàng)建NSURLSessionTask的子類對象。

4)執(zhí)行請求任務(wù)。

下面的示例展示了NSURLSession的基本用法,代碼如下:

-(void)sessionGet{

/*創(chuàng)建NSURL對象*/

NSURL*url=[NSURLURLWithString:IMAGEURL];

/*創(chuàng)建請求對象,默認(rèn)為GET請求*/

NSURLRequest*request=[NSURLRequestrequestWithURL:url];

/*創(chuàng)建配置*/

NSURLSessionConfiguration*config=[NSURLSessionConfigurationdefaultSessionConfigtwation];

/*創(chuàng)建NSURLSession對象*/

NSURLSession*session=[NSURLSessionsessionWithConfiguration:config];

/*創(chuàng)建任務(wù)*/

NSURLSessionDataTask*task=[sessiondataTaskWithRequest:requestcompletionHandler:^(NSData*_Nullabledata,NSURLResponse*_Nullableresponse,NSError*_Nullableerror){

if(error){

return;

}

/*解析返回的數(shù)據(jù)*/

_image=[UIImageimageWithData:data];

/*顯示圖片,注意!此時(shí)是異步線程需要在主線程中顯示圖片*/

[selfchangeBg];

}];

[taskresume];

}

7.

Objective-C對象可以被copy的條件是什么?正確答案:Objective-C對象可以被復(fù)制的條件是要遵守NSCopying和NSMutableCoping協(xié)議,默認(rèn)是不遵守的??梢韵蜃袷豊SCopying協(xié)議的類的實(shí)例發(fā)送copy消息,也可以向遵守NSMutableCopying協(xié)議的類的實(shí)例發(fā)送mutableCopy消息,如果沒有遵守協(xié)議而發(fā)送copy或mutableCopy消息,那么就會(huì)出錯(cuò)。兩個(gè)協(xié)議分別對應(yīng)不可變復(fù)制(copy)和可變復(fù)制(mutableCopy),而協(xié)議內(nèi)部的實(shí)現(xiàn)方式?jīng)Q定是深拷貝還是淺拷貝。

例如,典型的系統(tǒng)類NSAnay是同時(shí)遵守了NSCopying和NSMutableCopying協(xié)議的,因此既可以發(fā)送copy消息,也可以發(fā)送mutableCopy消息。此外,iOS中同時(shí)遵守NSCopying協(xié)議和NSMutableCopying協(xié)議的類還有:NSString、NSValue、NSDictionary和NSSet及其子類。

如果想自定義深拷貝或淺拷貝方法,那么就要先遵守對應(yīng)的協(xié)議,并重新實(shí)現(xiàn)對應(yīng)的協(xié)議方法。

NSCopying的協(xié)議方法為copyWithZone:

-(id)copyWithZone:(nullableNSZone*)zone{

//深拷貝或淺拷貝實(shí)現(xiàn)

}

NSMutableCopying的協(xié)議方法為mutableCopyWithZone:

-(id)mutableCopyWithZone:(nullableNSZone*)zone{

//深拷貝或淺拷貝實(shí)現(xiàn)

}

8.

Cocoa中有虛基類的概念嗎?正確答案:Cocoa中沒有虛基類的概念。虛基類是C++語言中為了解決多重繼承二義性問題的,而Objective-C中只有單繼承。

要實(shí)現(xiàn)類似C++語言中的多繼承,可以通過protocal來簡單實(shí)現(xiàn),因?yàn)橐粋€(gè)類可以實(shí)現(xiàn)多個(gè)協(xié)議,類似于Java中一個(gè)類可以實(shí)現(xiàn)多個(gè)接口。

9.

一般的方法method和Objective-C中的選擇器selector有什么區(qū)別?正確答案:selector是一個(gè)方法的名字,基于動(dòng)態(tài)綁定環(huán)境下;method是一個(gè)組合體,包含了名字和實(shí)現(xiàn)。

可以理解@selector()就是取類方法的編號,它的行為基本可以等同C語言的中函數(shù)指針,只不過C語言中,可以把函數(shù)名直接賦給一個(gè)函數(shù)指針,而Objective-C的類不能直接應(yīng)用函數(shù)指針,只能通過一個(gè)@selector語法來取,它的結(jié)果是一個(gè)SEL類型。這個(gè)類型本質(zhì)是類方法的編號(函數(shù)地址)。

10.

iOS中是如何使用自定義字體的?正確答案:字體是軟件開發(fā)中個(gè)性化的一個(gè)重要元素,系統(tǒng)自帶了很多豐富的字體,但有時(shí)候并不能滿足個(gè)性化的需求,這時(shí)候可以向工程中添加自定義的系統(tǒng)字體,然后就可以像使用系統(tǒng)字體一樣使用。字體文件最常用的為ttf等格式。

導(dǎo)入自定義字體過程很簡單:添加資源包到工程→在info.plist文件中注冊字體→在工程BundleResource中復(fù)制字體資源包→代碼檢測查詢加入的字體并使用。

1.添加資源包

addFile添加字體資源包或者直接將字體包拖到工程資源文件夾下(見圖1)。

圖1

字體文件拖入工程目錄

2.info.plist文件中注冊字體,添加字體資源包

在工程的info.plist屬性列表中添加Fontsprovidedbyapplication數(shù)組屬性,并在其下添加要加入的自定義字體項(xiàng)(見圖2和圖3)。注意,這里在plist文件中寫的是文件的全稱,包括文件擴(kuò)展名,文件的名字是可以隨便改的,但建議用本來的字體族名,例如這里是:KristenITC,字體族名是不會(huì)變的,之后具體代碼中使用的時(shí)候是用的字體族名而不是自定義的文件名。本來的字體族名可以右鍵查看字體文件的詳細(xì)信息,里面的全稱是本來的字體族名,而名稱是自定義的。字體注冊后將資源包復(fù)制到BundleResource即可(見圖3)。

圖2

配置info.plist

圖3

添加注冊自定義字體項(xiàng)

圖4

字體包復(fù)制到BundleResource

3.檢測是否成功加入字體

在具體使用之前,可以先通過UIFont類提供的方法打印出系統(tǒng)所有的字體列表,并找到剛添加的字體驗(yàn)證是否添加成功,還可以具體看到資源包有哪些具體的字體樣式,如該字體族的斜體、粗體、粗斜體等。打印字體族列表的代碼如下:

/*檢查自定義字體族是否成功加入*/

/*取出系統(tǒng)安裝了的所有字體族名*/

NSArray*familyNames=[UIFont=familyNames];

NSLog(@"系統(tǒng)所有字體族名:%@",familyNames);

/*打印字體族的所有子字體名(每種字體族可能對應(yīng)多個(gè)子樣式字體,例如每種字體族可能有粗體、斜體、粗斜體等等樣式)*/

for(NSString*familyNameinfamilyNames){

/*字體族的所有子字體名*/

NSArray*detailedNames=[UIFontfontNamesForFamilyName:familyName];

NSLog(@"\n字體族%@的所有了字體名:%@",familyName,detailedNames);

}

這里可以從字體組列表中找到剛添加的字體族KristenlTC,結(jié)果如圖5所示。

圖5

已有字體列表

還可以看到字體族KristenITC下的具體字體樣式,這里只有一種也是默認(rèn)的一種:KristenlTC-Regular(見圖6)。

圖6

字體名

4.使用字體

確定字體加入系統(tǒng)之后就可以像自帶的系統(tǒng)字體一樣直接使用了(字體效果如圖7所示)。

/*設(shè)置label的字體和大小f這里直接使用字體族名也是可以的,有默認(rèn)的子字體樣式,也可以根據(jù)需求具體到子字體例如這里的:KristenITC-Regular)*/

[_labelsetFont:[UIFontfontWithName:@"KristenITC"size:35.0]];

圖7

字體效果

11.

block有哪幾種定義的方式?正確答案:在Objective-C中,block定義包含了block的類型聲明和實(shí)現(xiàn),基本形式如下:

返回值類型(^block名稱)(參數(shù)類型)=^(參數(shù)類型和參數(shù)名){};

其中,返回值類型和參數(shù)可以是空。如果有參數(shù),那么在定義block的時(shí)候,必須要標(biāo)明參數(shù)的類型和參數(shù)名。所以,block大致有3種細(xì)分的定義方式。

1)沒有返回值,沒有參數(shù)的定義方式。

void(^myBlock)()=^{

//代碼

};

2)有返回值,有參數(shù)的定義方式。

int(^myBlock)(int)=^(inta){

returna;

};

3)有返回值,沒有參數(shù)的定義方式。

int(^myBlock)()=^{

return100;

};

當(dāng)然,block也有屬于自己的類型,就像在Objective-C中,字符串對象屬于NSString類型一樣。block類型的格式就是:

返回值類型(^)(參數(shù)類型)

也就是說,上面第一種定義方式的block類型就是void(^)(),myBlock不是變量名,而是這種block類型的別名。在Objective-C中,可以使用typedef關(guān)鍵字定義block類型,也可以直接使用inline提示符來自動(dòng)生成block格式。示例代碼如下:

/*使用typedef關(guān)鍵字定義block類型*/

typedefvoid(^myBloek)();

myBlockblock=^{

};

/*使用inline提示符來自動(dòng)生成block格式*/

<#retumType#>(^<#blockName#>)(<#parameterTypes#>)=^(<#parameters#>){

<#statements#>

};

12.

什么是內(nèi)存泄漏?什么是安全釋放?正確答案:內(nèi)存泄漏指動(dòng)態(tài)分配內(nèi)存的對象在使用完后沒有被系統(tǒng)回收內(nèi)存,導(dǎo)致該對象始終占用內(nèi)存,又無法通過代碼訪問,屬于內(nèi)存管理出錯(cuò),如果出現(xiàn)大量內(nèi)存泄漏,那么會(huì)導(dǎo)致系統(tǒng)內(nèi)存不足的問題。由于內(nèi)存泄漏的檢測是程序開發(fā)中不可避免的問題,所以對于程序員而言,一方面要深入理解內(nèi)存管理原則,養(yǎng)成良好的編程習(xí)慣以減少內(nèi)存泄漏情況的發(fā)生;另一方面可以通過各種方法,例如使用Xcode提供的檢測調(diào)試工具Instruments,檢測可能導(dǎo)致內(nèi)存泄漏的代碼,并及時(shí)進(jìn)行優(yōu)化。

安全釋放指釋放掉不再使用的對象的同時(shí)不會(huì)造成內(nèi)存泄漏或指針懸掛問題的操作。為了保證安全釋放,在對象dealloc后要將其指針置為nil。另外,要嚴(yán)格遵守內(nèi)存管理原則,保證對象的引用計(jì)數(shù)正確,同時(shí)要注意避免引用循環(huán)的出現(xiàn)。

13.

一個(gè)tableView是否可以關(guān)聯(lián)兩個(gè)不同的datasource數(shù)據(jù)源?正確答案:多個(gè)數(shù)據(jù)源是完全可以的,問題的重點(diǎn)是如何關(guān)聯(lián),因?yàn)閷?shù)據(jù)源(Model)和tableView視圖的對接工作是程序員完成的,所以數(shù)據(jù)源的多少?zèng)]有根本影響。處理上可以分開依次對接,也可以通過數(shù)據(jù)的集合操作先將數(shù)據(jù)整理合并成一個(gè)數(shù)據(jù)源,然后對接。

例如,一個(gè)表格中的每個(gè)cell顯示的是一個(gè)人的基本信息,為了簡單這里假設(shè)只有一個(gè)頭像和I一個(gè)姓名。假設(shè)有兩個(gè)數(shù)據(jù)源,一個(gè)數(shù)據(jù)源是頭像的url數(shù)組;另一個(gè)是姓名的字符串?dāng)?shù)組,對接時(shí)完全可以分開在cell數(shù)據(jù)回調(diào)中對接,也可以將兩個(gè)數(shù)組合并然后對接。

合并數(shù)據(jù)用到的數(shù)據(jù)模型:

@interfaceModel:NSObject

@property(nonatomic,copy)NSString*name;

//姓名

@property(nonatomic,copy)NSString*url;

//圖片

@end

數(shù)據(jù)源緩沖器:

/*數(shù)據(jù)源*/

@property(nonatomic,strong)NSArray*nmne_datasource;

@property(nonatomic,strong)NSArray*url_datasource;

@property(nonatomic,strong)NSMutableArray*datasource;

處理多數(shù)據(jù)源:

/*請求數(shù)據(jù)*/

-(void)request{

/*姓名數(shù)據(jù)源*/

_name_datasource=@[@"張三",@"李四",@"小明",@"小李"];

_url_datasource=@[@"male",@"male",@"male",@"male"];

/*合并數(shù)據(jù)源*/

for(inti;i<_name_datasource.count;i++){

Model*model=[[Modelalloc]init];

=_name_datasource[i];

model.url=_url_datasource[i];

[_datasourceaddObject:model];

}

}

數(shù)據(jù)對接:

/*cell數(shù)據(jù)回調(diào)*/

-(UITableViewCell*)tableView:(UITableView*)tableViewcellForRowAtIndexPath:(NSIndexPath*)indexPath{

staticNSString*identifier=@"identifier";

/*自制cell組件*/

AccountCell*cell=[[AccountCellalloc]initWithStyle:UITableViewCellStyleDefaultreuseIdentifier:identifier];

/**多數(shù)據(jù)源分開對接:**/

/*頭像*/

[cell.avatarsetImage:[UIImageimageNamed:_url_datasource[indexPath.row]];

/*姓名*/

.text=_name_datasource[indexPath.row];

/*或者:*/

/**數(shù)據(jù)源合并后對接**/

/*取出對應(yīng)數(shù)據(jù)模型*/

Model*model=_datasource[indexPath.row];

/*頭像*/

[cell.avatarsetImage:[UIImageimageNamed:model.url]];

/*姓名*/

.text=;

returncell;

}

14.

Objective-C中的NSInteger類型和C語言中的int類型有什么區(qū)別?正確答案:在Objective-C中,數(shù)據(jù)類型可以分為基本數(shù)據(jù)類型、對象類型和id類型?;緮?shù)據(jù)類型有int類型、float類型、double類型、char類型、布爾類型等。事實(shí)上,Objective-C中的NSInteger也是基本數(shù)據(jù)類型之一。在蘋果的API實(shí)現(xiàn)中,NSInterger是一個(gè)對int類型和long類型的封裝,它會(huì)識(shí)別當(dāng)前操作系統(tǒng)的位數(shù),自動(dòng)返回最大的類型。定義NSInteger類型的代碼如下:

#if__LP64__||(TARGET_OS_EMBEDDED&&!TARGET_OS_IPHONE)||TARGET_OS_WIN32||NS_BUILD_32_LIKE_64

typedeflongNSInteger;

typedefunsignedlongNSUInteger;

#else

typedefintNSInteger;

typedefunsignedintNSUInteger;

#endif

其中,#if、#else、typedef等都屬于預(yù)處理語言。上面這段代碼的意思是,當(dāng)系統(tǒng)是32位系統(tǒng)時(shí),NSInteger類型等價(jià)于int類型,即32位,但當(dāng)系統(tǒng)是64位時(shí),NSInteger類型等價(jià)于long類型,即64位。

可以看出,NSInteger是long或者int的別名,對應(yīng)的NSUInteger是unsignedlong或者unsignedint的別名。區(qū)別在于,NSInteger會(huì)根據(jù)系統(tǒng)是32位機(jī)還是64位機(jī)來動(dòng)態(tài)確定自身是整型還是長整型,從而可以很好地兼容兩種機(jī)器。因此,當(dāng)開發(fā)者不知道操作系統(tǒng)是什么類型的時(shí)候,通常應(yīng)該使用NSInteger,這也是蘋果公司推薦使用的基本數(shù)據(jù)類型之一。

另外,NSInteger是Objective-C基本數(shù)據(jù)類型,不是NSNumber的子類,也不是NSObject的子類。

15.

如何檢測內(nèi)存泄漏?正確答案:檢測內(nèi)存泄漏主要有以下3種方法:

1.靜態(tài)分析

通過靜態(tài)分析可以初步地了解到代碼的一些不規(guī)范的地方或者是存在內(nèi)存泄漏的地方,這是對內(nèi)存泄漏的第一步檢測。當(dāng)然有一些警告是不需要關(guān)心的,可以略過。

2.通過instruments來檢查內(nèi)存泄漏

這個(gè)方法能粗略地定位在哪里發(fā)生了內(nèi)存泄漏。方法是完成一個(gè)循環(huán)操作,如果內(nèi)存增長為0,那么就證明程序在該次循環(huán)操作中不存在內(nèi)存泄漏;如果內(nèi)存增長不為0,那么就證明有可能存在內(nèi)存泄漏。當(dāng)然具體問題需要具體分析。

3.代碼測試內(nèi)存泄漏

在做這項(xiàng)工作之前,要注意在dealloc的方法中是否已經(jīng)釋放了該對象所擁有的所有對象。觀察對象的生成和銷毀是否配對。準(zhǔn)確地說,就是init(創(chuàng)建對象的方法)和dealloc是否會(huì)被成對觸發(fā)(簡單來說就是有一次創(chuàng)建對象就有一次dealloc該對象)。

16.

隱式動(dòng)畫的實(shí)現(xiàn)原理是什么?如何禁用圖層的隱式動(dòng)畫?正確答案:在iOS程序開發(fā)中,有時(shí)僅僅改變了圖層或者視圖的一個(gè)動(dòng)畫屬性(例如backgroundColor),就會(huì)發(fā)現(xiàn)屬性是平滑地過渡到目標(biāo)值的,屬性值的改變產(chǎn)生了一個(gè)動(dòng)畫效果,而實(shí)際上開發(fā)者并沒有顯式地使用動(dòng)畫,這就是隱式動(dòng)畫的作用。

隱式動(dòng)畫指當(dāng)更改視圖的非根圖層的可動(dòng)畫屬性時(shí),CoreAnimation自動(dòng)決定如何并且何時(shí)去做動(dòng)畫。動(dòng)畫的執(zhí)行時(shí)間取決于當(dāng)前事務(wù)(CATransaction),而動(dòng)畫類型取決于圖層行為。

CATransaction類是用來包含一系列屬性動(dòng)畫集合的機(jī)制,任何用指定事務(wù)去改變可動(dòng)畫屬性都不會(huì)立即發(fā)生變化,而是當(dāng)事務(wù)提交的時(shí)候開始用一個(gè)動(dòng)畫過渡到新值。CATransaction類沒有屬性或者實(shí)例方法,也不能用+alloc和-init方法創(chuàng)建,但是可以用+begin和+commit方法分別來入棧和出棧,這類似于UIView的+beginAnimations:context:和+commitAnimations方法。其次,還可以用+setAnimationDuration方法設(shè)置當(dāng)前事務(wù)的動(dòng)畫時(shí)間,或者+animationDuration方法來獲取值。

改變屬性是CALayer自動(dòng)應(yīng)用的動(dòng)畫被稱為“行為”。當(dāng)CALayer的屬性被修改的時(shí)候,它會(huì)調(diào)用actionForKey:方法,傳遞屬性的名稱。具體的實(shí)現(xiàn)原理分為以下幾步:

1)圖層會(huì)檢測其是否有代理,并且代理是否實(shí)現(xiàn)了CALayerDelegate協(xié)議指定的-actionForLayer:forKey方法。如果有,那么直接調(diào)用并返回結(jié)果。

2)如果圖層沒有代理,或者代理沒有實(shí)現(xiàn)-actionForLayer:forKey:方法,那么圖層會(huì)接著檢查包含屬性名稱對應(yīng)行為映射的actions字典。

3)如果actions字典沒有包含對應(yīng)的屬性,那么圖層接著在它的style字典搜索屬性名。

4)最后,如果在style字典中也沒有找到對應(yīng)的行為,那么圖層將會(huì)直接調(diào)用定義每個(gè)屬性的標(biāo)準(zhǔn)行為的-defaultActionForKey:方法。

于是就可以解釋UIKit是如何禁用隱式動(dòng)畫的:每個(gè)UIView都是其根圖層的代理,并且實(shí)現(xiàn)了-actionForLayer:forKey:方法,只不過返回nil,也就是不執(zhí)行任何動(dòng)畫。

除了在-actionForLayer:forKey:方法的實(shí)現(xiàn)中返回nil外,還可以通過CATransaction的方法+setDisableActions來打開或者關(guān)閉屬性的隱式動(dòng)畫。使用+setDisableActions臨時(shí)取消隱式動(dòng)畫的代碼如下:

-(void)viewDidLoad{

[superviewDidLoad];

_colorLayer=[CALayerlayer];

_colorLayer.bounds=CGRectMake(0,0,200,200);

_colorLayer.position=self.view.center;

_colorLayer.baekgroundeolor=[UIColorredColor].CGColor;

_colorLayer.delegate=self;

[self.view.layeraddSublayer:_colorLayer];

}

-(void)touchesBegan:(NSSet<UITouch*>*)toucheswithEvent:(UIEvent*)event{

[CATransactionbegin];

//關(guān)閉隱式動(dòng)畫

CATransaction.disableActions=YES;

CATransaction.animationDuration=5;

_colorLayer.backgroundColor=randomColor.CGColor;

[CATransactioncommit];

}

17.

GCD多線程編程中什么時(shí)候會(huì)創(chuàng)建新線程?正確答案:對于是否會(huì)開啟新線程的情景主要有如下幾種情況:串行隊(duì)列中提交異步任務(wù)、串行隊(duì)列中提交同步任務(wù)、并發(fā)隊(duì)列中提交異步任務(wù)、并發(fā)隊(duì)列中提交同步任務(wù)。

(其中主隊(duì)列是典型的串行隊(duì)列,全局隊(duì)列是典型的并發(fā)隊(duì)列)

/*創(chuàng)建一個(gè)串行隊(duì)列*/

dispatch_queue_tserialQueue=dispatch_queue_create("serial.queue".DISPATCH_QUEUE_SERIAL);

/*創(chuàng)建一個(gè)并發(fā)隊(duì)列*/

dispatch_queue_tconcurrentQueue=dispatch_queue_create("concurrent.queue",DISPATCH_QUEUE_CONCURRENT);

1)串行隊(duì)列中提交同步任務(wù):不會(huì)開啟新線程,直接在當(dāng)前線程同步地串行執(zhí)行這些任務(wù)。

/*1串行隊(duì)列添加同步任務(wù):沒有開肩新線程,全部在主線程串行執(zhí)行*/

dispatch_sync(serialQueue,^{

NSLog(@"SERIAL_SYN_A%@",[NSThreadcurrentThread]);

});

dispatch_sync(serialQueue,^{

NSLog(@"SERIAL_SYN_B%@",[NSThreadcurrentThread]);

});

dispatch_sync(serialQueue,^{

NSLog(@"SERIAL_SYN_C%@",[NSThreadcurrentThread]);

});

2)串行隊(duì)列中提交異步任務(wù):會(huì)開啟一個(gè)新線程,在新子線程異步地串行執(zhí)行這些任務(wù)。

/*2串行隊(duì)列添加異步任務(wù):開啟了一個(gè)新子線程并共用,串行執(zhí)行*/

dispatch_async(serialQueue,^{

NSLog(@"SERIAL_ASYN_A%@",[NSThreadcurrentThread]);

});

dispatch_async(serialQueue,^{

NSLog(@"SERfAL_ASYN_B%@",[NSThreadcurrentThread]);

});

dispatch_async(serialQueue,^{

NSLog(@"SERIAL_ASYN_C%@",[NSThreadcurrentThread]);

});

3)并發(fā)隊(duì)列中提交同步任務(wù):不會(huì)開啟新線程,效果和“串行隊(duì)列中提交同步任務(wù)”一樣,直接在當(dāng)前線程同步地串行執(zhí)行這些任務(wù)。

/*3并發(fā)隊(duì)列添加同步任務(wù):沒有開啟新線程,全部在主線程串行執(zhí)行*/

dispatch_sync(concurrentQueue,^{

NSLog(@"CONCURRENT_SYN_A%@",[NSThreadcurrentThread]);

});

dispatch_sync(concurrentQueue,^{

NSLog(@"CONCURRENT_SYN_B%@",(NSThreadcurrentThread]);

});

dispatch_sync(concurrentQueue,^{

NSLog(@"CONCURRENT_SYN_C%@",[NSThreadcurrentThread]);

});

4)并發(fā)隊(duì)列中提交異步任務(wù):會(huì)開啟多個(gè)子線程,在子線程異步地并發(fā)執(zhí)行這些任務(wù)。

/*4并發(fā)隊(duì)列添加異步任務(wù):開啟多個(gè)子線程,并發(fā)執(zhí)行多個(gè)任務(wù)*/

dispatch_async(concurrentQueue,^{

NSLog(@"CONCURRENT_ASYN_A%@",[NSThreadcurrentThread]);

});

dispatch_async(concurrentQueue,^{

NSLog(@"CONCURRENT_ASYN_B%@",[NSThreadcurrentThread]);

});

dispatch_async(concurrentQueue,^{

NSLog(@"CONCURRENT_ASYN_C%@",[NSThreadcurrentThread]);

});

下圖展示了上面例子中線程的執(zhí)行順序。

線程執(zhí)行順序

總結(jié):

只有異步提交任務(wù)時(shí)才會(huì)開啟新線程,異步提交到串行隊(duì)列會(huì)開啟一個(gè)新線程,異步提交到并發(fā)隊(duì)列可能會(huì)開啟多個(gè)線程。

同步提交任務(wù)無論提交到并發(fā)隊(duì)列還是串行隊(duì)列,都不會(huì)開啟新線程,都會(huì)直接在當(dāng)前線程依次同步執(zhí)行。

注意,如果當(dāng)前線程是主線程,那么不可在當(dāng)前線程提交同步任務(wù),否則會(huì)造成線程死鎖而報(bào)錯(cuò)。

18.

Objective-C有私有方法嗎?有私有變量嗎?正確答案:Objective-C是否有私有方法和私有變量關(guān)鍵要看私有的定義。私有主要指通過類的封裝性,將不希望讓外界看到的方法或?qū)傩噪[藏在類內(nèi)部,只有該類可以在內(nèi)部訪問,外部不可見不可訪問。

表面上看,Objective-C中是可以實(shí)現(xiàn)私有的變量和方法的,即將它們隱藏不暴露在頭文件中,不可以顯式地直接訪問,但是Objective-C中這種私有并不是絕對的私有,例如即使將變量和方法隱藏在.m實(shí)現(xiàn)文件中,開發(fā)者仍然可以利用KVC或runtime運(yùn)行時(shí)機(jī)制強(qiáng)行訪問沒有暴露在頭文件的變量或方法。

Objective-C中實(shí)現(xiàn)變量和方法“私有”的方式主要有兩種。

1)在類的頭文件中聲明私有變量。

#import<Foundation/Foundation.h>

@interfaceTest:NSObject{

/*頭文件中定義私有變量,默認(rèn)為@protected*/

@private

NSString*major;

}

@end

2)在.m實(shí)現(xiàn)文件頭部的類擴(kuò)展區(qū)域定義私有屬性或方法,其中方法可不用聲明,直接在實(shí)現(xiàn)文件中實(shí)現(xiàn)即可,只要不在頭文件聲明的方法都對外不可見。

#import"Test.h"

@interfaceTest(){

/*類擴(kuò)展區(qū)域定義私有變量,默認(rèn)就是@private*/

intage;

}

/*類擴(kuò)展區(qū)域定義私有屬性*/

@property(nonatomic,copy)NSString*name;

/*類擴(kuò)展區(qū)域定義私有實(shí)例方法(可省略聲明,類方法的作用主要就是提供對外接口的,所以一般不會(huì)定義為私有)*/

-(void)test;

@end

@implementationTest

/*私有實(shí)例方法*/

-(void)test{

NSLog(@"這是個(gè)私有實(shí)例方法!");

}

@end

利用KVC和runtime暴力訪問私有屬性和變量

KVC訪問變量不受私有權(quán)限的限制,訪問代碼如下:

#import"Test.h"

#import<o(jì)bjc/runtime.h>

...

Test*test=[[Testalloc]ink];

/*1.KVO暴力訪問私有屬性和私有變量*/

[testsetValue:@"albert"forKeyPath:@"name"];

NSString*pname=[testvalueForKey:@"name"];

[testsetValue:@"mathmetics"forKeyPath:@"major"];

NSString*pmajor=[testvalueForKey:@"major"];

NSLog(@"pname:%@pmajor:%@",pname,pmajor);

程序的運(yùn)行結(jié)果為:

2017-04-0211:58:56.255723CommandLine[99973:3239125]pname:albertpmajor:mathmetics

運(yùn)行時(shí)可以使用class_copyIvarList函數(shù)獲取類對象的Ivar變量列表,然后可使用object_getIvar和object_setIvar運(yùn)行時(shí)函數(shù)對變量進(jìn)行暴力訪問。

#import"Test.h"

#import<o(jì)bjc/runtime.h>

...

Test*test=[[Testalloc]init];

/*2.運(yùn)行時(shí)暴力訪問私有屬性和私有變量(ARC)*/

/*獲取實(shí)例變量列表*/

unsignedintcount=0;

Ivar*members=class_copyIvarList([Testclass],&count);

/*打印所有的變量名及其類型*/

for(inti=0;i<count;i++){

constchar*memberName=ivar_getName(members[i]);

constchar*memberType=ivar_getTypeEncoding(members[i]);

NSLog(@"name:%stype:%s",memberName,memberType);

}

/*訪問私有屬性和變量*/

Ivarv

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論