iOS最新面試題解答最全-2023-02

五、APP生命周期

APP有5種狀態(tài),分別是:
1、Not running未運行:app沒啟動或被迫終止。
2、Inactive未激活:當前應用正在前臺運行,但是并不接收事件(當前或許正在執(zhí)行其它代碼)。一般每當應用要從一個狀態(tài)切換到另一個不同的狀態(tài)時,中途過渡會短暫停留在此狀態(tài)。唯一在此狀態(tài)停留時間比較長的情況是:當用戶鎖屏時,或者系統(tǒng)提示用戶去響應某些(諸如電話來電、有未讀短信等)事件的時候。
3、Active激活:當前應用正在前臺運行,并且接收事件。這是應用正在前臺運行時所處的正常狀態(tài)。
4、Backgroud后臺:程序在后臺而且能執(zhí)行代碼,大多數(shù)程序進入這個狀態(tài)后會在在這個狀態(tài)上停留一會。時間到之后會進入掛起狀態(tài)(Suspended)。經過特殊的請求后可以長期處于Backgroud狀態(tài)。
5、Suspended掛起:程序在后臺不能執(zhí)行代碼。系統(tǒng)會自動把程序變成這個狀態(tài)而且不會發(fā)出通知。當掛起時,程序還是停留在內存中的,當系統(tǒng)內存低時,系統(tǒng)就把掛起的程序清除掉,為前臺程序提供更多的內存。


中.png

applicationDidEnterBackground:方法允許最多有5秒的時間去完成任何任務然后返回。實際中,此方法應該盡可能快的返回。如果在時間到期之后,此方法沒有返回,則應用即被kill掉,并且清除所占用的內存。如果你的應用確實需要更多的時間去執(zhí)行任務,可以調用beginBackgroundTaskWithExpirationHandler:方法請求后臺執(zhí)行時間,然后啟動一個能長期執(zhí)行任務的線程。無論你是否啟動一個執(zhí)行后臺任務的線程,applicationDidEnterBackground:方法都必須在5秒后退出。

UIViewController生命周期,子視圖布局在哪里布局?是在哪個方法?方法是在什么時機調用

代碼調用順序
- (instancetype)initWithNibName:(nullable NSString *)nibNameOrNil bundle:(nullable NSBundle *)nibBundleOrNil
- (void)loadView;
- (void)viewDidLoad;
- (void)viewWillAppear:(BOOL)animated; 
- (void)viewWillLayoutSubviews API_AVAILABLE(ios(5.0));
// Called just after the view controller's view's layoutSubviews method is invoked. Subclasses can implement as necessary. The default is a no-op.
addSubViews:會調用此方法
控制器將要布局子控件,默認不進行任何操作。你可以在LayoutSubviews之前重寫此方法布局子視圖。
- (void)viewDidLayoutSubviews API_AVAILABLE(ios(5.0));
- (void)viewDidAppear:(BOOL)animated; 
- (void)viewWillDisappear:(BOOL)animated; // Called when the view is dismissed, covered or otherwise hidden. Default does nothing
- (void)viewDidDisappear:(BOOL)animated; 
- (void)didReceiveMemoryWarning; // Called when the parent application receives a memory warning. On iOS 6.0 it will no longer clear the view by default.
dealloc
image.png

-layoutSubvlews:默認沒有做任何事情,需要子炎進行重寫.png

layoutSubviews對subvlews重新布局.png

六、講講runtime,有什么體現(xiàn)

Runtime的特性主要是消息(方法)傳遞,如果消息(方法)在對象中找不到,就進行轉發(fā)


Runtimo消息傳涕.png

Runtimo消息轉發(fā).png

動態(tài)方法解析
首先,Objective-C運行時會調用 +resolveInstanceMethod:或者 +resolveClassMethod:,讓你有機會提供一個函數(shù)實現(xiàn)。如果你添加了函數(shù)并返回YES, 那運行時系統(tǒng)就會重新啟動一次消息發(fā)送的過程。
如果resolve方法返回 NO ,運行時就會移到下一步:forwardingTargetForSelector。
完整消息轉發(fā)
如果在上一步還不能處理未知消息,則唯一能做的就是啟用完整的消息轉發(fā)機制了。首先它會發(fā)送-methodSignatureForSelector:消息獲得函數(shù)的參數(shù)和返回值類型。如果-methodSignatureForSelector:返回nil ,Runtime則會發(fā)出 -doesNotRecognizeSelector: 消息,程序這時也就掛掉了。如果返回了一個函數(shù)簽名,Runtime就會創(chuàng)建一個NSInvocation 對象并發(fā)送 -forwardInvocation:消息給目標對象。

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    if ([NSStringFromSelector(aSelector) isEqualToString:@"foo"]) {
        return [NSMethodSignature signatureWithObjCTypes:"v@:"];//簽名,進入forwardInvocation
    }
    
    return [super methodSignatureForSelector:aSelector];
}

- (void)forwardInvocation:(NSInvocation *)anInvocation {
    SEL sel = anInvocation.selector;

    Person *p = [Person new];
    if([p respondsToSelector:sel]) {
        [anInvocation invokeWithTarget:p];
    }
    else {
        [self doesNotRecognizeSelector:sel];
    }

}

method 的實現(xiàn)機制

Method 是一個objc_method結構體,objc_method是類的一個方法描述
SELOC在編譯的時候,會根據方法簽名(參數(shù)類型),生成一個用來區(qū)分這個方法的唯一的一個ID,本質上就是一個字符串,這個ID就是SEL類型的,在運行的時候是通過方法的ID來查找方法的,只要方法的簽名相同,那么它們的ID都是相同的;不管是超類還是子類,還是其他類,只要簽名相同那么ID就是一樣的

不同的類可以擁有相同的selector, 不同的類的實例對象performSelector相同的selector時,會在各自的方法鏈表中根據selector去查找具體的方法實現(xiàn)IMP,然后用這個方法實現(xiàn)去執(zhí)行具體的實現(xiàn)代碼

1.在OC中想要得到方法的SEL可以直接使用@selector指示符,SEL act = @selector(setAage:)2.使用函數(shù) NSSelectorFromString(@“setAge:”)3.SEL類型的方法名使用函數(shù)(NSString *)NSStringFromSelector(SEL)4.SEL轉成函數(shù)指針 IMP imp_setAge = [self methodForSelector:@selector(setAge:)]
IMP一個函數(shù)指針,指向方法實現(xiàn)的首地址

通過取得IMP,我們可以跳過runtime的消息傳遞機制,直接執(zhí)行IMP指向的函數(shù)實現(xiàn),這樣省去了runtime消息傳遞過程中所做的一系列查找操作,會比直接向對象發(fā)送消息的效率高一些
方法的調用流程

  •   檢測selector是否需要忽略
    
  •   檢查target是否nil,如果是nil就直接cleanup,然后return
    
  •   在target的Class中根據selector去找IMP尋找IMP的過程:1、在當前class的方法緩存里面尋找(cache methodLists)2、找到了跳到對應的方法實現(xiàn),沒找到繼續(xù)往下執(zhí)行3、從當前class的方法列表里查找(methodLists),找到了添加到緩存列表里,然后跳轉到對應的方法實現(xiàn);沒找到繼續(xù)往下執(zhí)行4、從superClass的緩存列表和方法列表里查找,直到找到基類為止,不論是在cache methodLists還是methodLists中找到IMP,都會先存入當前class的cache methodList在跳轉到對應的方法實現(xiàn)5、以上步驟還找不到IMP,則進入到消息動態(tài)處理和消息轉發(fā)流程
    

iOS中內省的幾個方法?class方法和objc_getClass方法有什么區(qū)別

Pasted Graphic 2.png
struct category_t {
const char *name; //名字
classref_t cls; //類的引用
struct method_list_t *instanceMethods;//實例方法列表
struct method_list_t *classMethods;//類方法列表
struct protocol_list_t *protocols;//協(xié)議列表
struct property_list_t *instanceProperties;//實例屬性列表

struct property_list_t *_classProperties;//類屬性列表
};

分類的實現(xiàn)原理是將category中的方法,屬性,協(xié)議數(shù)據放在category_t結構體中,然后將結構體內的方法列表拷貝到類對象的方法列表中。
Category可以添加屬性,但是并不會自動生成成員變量及set/get方法。因為category_t結構體中并不存在成員變量。通過之前對對象的分析我們知道成員變量是存放在實例對象中的,并且編譯的那一刻就已經決定好了。而分類是在運行時才去加載的。那么我們就無法再程序運行時將分類的成員變量中添加到實例對象的結構體中。因此分類中不可以添加成員變量。

self與super的區(qū)別

sal 維粉一個園城參款。都個方的安機功第一個參量物方。.png

image.png

weak的實現(xiàn)原理

。3.期發(fā)計。有國 148eg1 Rc Lg l,Gleartealocating 海就維大糖康許魚城城我都路有 看i抽啡的教康,熱精速味速個餐通配期。.png

Runtime應用

應用場景。

  • 關聯(lián)對象(Objective-C Associated Objects)給分類增加屬性
  • 方法魔法(Method Swizzling)方法添加和替換和KVO實現(xiàn)
  • 消息轉發(fā)(熱更新)解決Bug(JSPatch)
  • 實現(xiàn)NSCoding的自動歸檔和自動解檔
  • 實現(xiàn)字典和模型的自動轉換(MJExtension)

在 iOS中可以直接調用某個對象的消息方式有兩種:

一種是performSelector:withObject;
再一種就是NSInvocation。
第一種方式比較簡單,能完成簡單的調用。但是對于>2個的參數(shù)或者有返回值的處理,那performSelector:withObject就顯得有點有心無力了,那么在這種情況下,我們就可以使用NSInvocation來進行這些相對復雜的操作
// 方法簽名中保存了方法的名稱/參數(shù)/返回值,協(xié)同NSInvocation來進行消息的轉發(fā)

// 方法簽名一般是用來設置參數(shù)和獲取返回值的, 和方法的調用沒有太大的關系
//1、根據方法來初始化NSMethodSignature
NSMethodSignature  *signature = [ViewController instanceMethodSignatureForSelector:@selector(run:)];
// NSInvocation中保存了方法所屬的對象/方法名稱/參數(shù)/返回值
//其實NSInvocation就是將一個方法變成一個對象
//2、創(chuàng)建NSInvocation對象
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
//設置方法調用者
invocation.target = self;
//注意:這里的方法名一定要與方法簽名類中的方法一致
invocation.selector = @selector(run:);
NSString *way = @"byCar";
//這里的Index要從2開始,以為0跟1已經被占據了,分別是self(target),selector(_cmd)
[invocation setArgument:&way atIndex:2];
//3、調用invoke方法
[invocation invoke];
//實現(xiàn)run:方法
- (void)run:(NSString *)method{
    
}

七、講講runloop

詳細鏈接
runloop,運行循環(huán),可使線程能隨時處理時間但并不退出,這也就是手機app在運行時不會退出的原因。當沒有事件時,runloop會進入休眠狀態(tài),有事件發(fā)生時,runloop再進行相應的處理事件。runloop可以讓線程在需要做事的時候忙起來,不需要的時候讓線程休眠。

Runloop的底層數(shù)據結構(NSRunLoop是CFRunLoop的封裝):
CFRunLoop,RunLoop對象
Mode,運行模式
Source,輸入源/事件源
Timer,定時源
Observer,觀察者
系統(tǒng)默認注冊了5個Mode常用的有3個 常見的幾種Mode:
Default : App的默認Mode,通常主線程是在這個Mode下運行
UITracking: 界面跟蹤Mode,用于ScrollView`追蹤觸摸滑動,保證界面滑動時不受其他Mode影響。
Common :并不是一個真的模式,它只是一個標記,如:被標記的 Timer可以在Default模式和UITracking下運行。

八、講講assign,weak區(qū)別,講講淺拷貝,深拷貝有什么區(qū)別

[NSArray copy] 淺copy
[NSArray mutableCopy] 深copy
[NSMutableArray copy] 深copy
[NSMutableArray mutableCopy] 深copy

九、將block和delegate的區(qū)別,__block有什么作用

91.block 的內存管理.png

n食 有便有用啡通的期館).png

1.當回調函數(shù)多于3個的時候,采用代理比較好
2.使用代碼塊容易造成循環(huán)引用,代理不會出現(xiàn)該問題
3.其他情況下優(yōu)先考慮代碼塊
1.從源頭上理解和區(qū)別block和delegate
delegate運行成本低,block的運行成本高。
block出棧需要將使用的數(shù)據從棧內存拷貝到堆內存,當然對象的話就是加計數(shù),使用完或者block置nil后才消除。delegate只是保存了一個對象指針,直接回調,沒有額外消耗。就像C的函數(shù)指針,只多做了一個查表動作。
2.從使用場景區(qū)別block和delegate
有多個相關方法。假如每個方法都設置一個 block, 這樣會更麻煩。而 delegate 讓多個方法分成一組,只需要設置一次,就可以多次回調。當多于 3 個方法時就應該優(yōu)先采用 delegate。當1,2個回調時,則使用block。
delegate更安全些,比如: 避免循環(huán)引用。使用 block 時稍微不注意就形成循環(huán)引用,導致對象釋放不了。這種循環(huán)引用,一旦出現(xiàn)就比較難檢查出來。而 delegate 的方法是分離開的,并不會引用上下文,因此會更安全些。
delegate回調返回的參數(shù)被限制在了 NS 類的范圍內,數(shù)量也很有限(當然可以用直接調用方法的形式在繞過,并不推薦;也可以用 Array 套著傳, 不過這樣需要有文檔支持,不然不夠清晰,回調方法也需要獨立的驗證,故也不推薦)。

通過上面的知識,可以簡單說他們的區(qū)別,block適合少數(shù)回調,需要運行內存,多次回調容易出現(xiàn)循環(huán)引用 delegate回調次數(shù)不限制,回調對象需要知道當前回調對象,delegate很安全不會引用上下文。
1.分析,ARC如果在塊對象中使用了__block指定的變量,那么這個變量將會被copy到堆內存中,并且原變量也會指向這個堆內存中的空間

十、講講gcd是怎么開辟線程,底層是怎么實現(xiàn)的

同步執(zhí)行方式是不創(chuàng)建新線程的,就在當前線程嗨。
線程按執(zhí)行方式分為同步、異步,按隊列管理分為串行并行,這樣有四種組合,加上常說的主線程主隊列,那么結合執(zhí)行方式就有六種組合。
同步串行,不創(chuàng)建線程,所以還是在當前線程一個一個做
同步并行,不創(chuàng)建線程,所以就算是并行,也還是在當前線程一個一個做
異步串行,開辟多一條線程,任務在新開辟的一條線程里面一個一個做
異步并行,開辟多條線程,任務在新開辟的線程里面一起做
同步主隊,阻塞
異步主隊,同異步串行,因為主隊就是串行,但是不開辟新線程,因為主線程是全局的單例的
2>GCD 只支持 FIFO(先進先出) 的隊列,NSOperationQueue 可以很方便地調整執(zhí) 行順序、設置最大并發(fā)數(shù)量
在異步線程中下載很多圖片,如果失敗了,該如何處理?請結合RunLoop來談談解決方案
1> 重新下載圖片
2>下載完畢, 利用 RunLoop 的輸入源(輸入源(input source)(傳遞異步事件))回到主線程刷新 UIImageVIUew

NSOperation是怎么處理最大并發(fā)數(shù)和線程依賴(用GCD實現(xiàn))

最大并發(fā)數(shù):用信號量控制最大數(shù),如果并發(fā)數(shù)設置為4,那信號量為3,執(zhí)行完了發(fā)送信號量不然就等著
線程依賴:使用調度組dispatch_group_create和GCD中的柵欄和wait也能實現(xiàn)同樣的效果

十一、講講ARC的原理

自動的引用計數(shù)


85.NSString 用 copy 和 strong 的區(qū)別.png

如果放一張很大的圖在項目加載,怎么才能檢查到那個內存暴漲,哪個方法出現(xiàn)內存暴漲

利用Xcode自帶的instrument檢查內存占用情況,并定位內存不斷增大的原因
點擊profile。出現(xiàn)如下界面,選Allocations instrument
內存泄露 Instruments之Leaks

NULL 是宏,是對于 C語富指針而使用的,表示空指針.png

十二、講講有哪些區(qū)?全局變量,局部變量,靜態(tài)變量存放在哪里

棧是先進后出的隊列
堆都是動態(tài)分配的,沒有靜態(tài)分配的堆。棧有兩種分配方式:靜態(tài)分 配和動態(tài)分配。靜態(tài)分配是編譯器完成的,比如局部變量的分配。動 態(tài)分配是有 alloc 函數(shù)進行分配的
局部變量:棧區(qū)
局部靜態(tài)變量:靜態(tài)區(qū)
全局變量:靜態(tài)區(qū)的常量區(qū)
全局靜態(tài)變量:靜態(tài)區(qū)
內存分四個區(qū):靜態(tài)區(qū),棧區(qū),堆區(qū),代碼區(qū)

75.簡述內存分區(qū)情況.png

d、一個有10個整型數(shù)的數(shù)組 inta[10];
e、一個有10個指針的數(shù)組,該指針是指向一個整型數(shù)的 inta[10];
f、一個指向有10個整型數(shù)數(shù)組的指針 int(
a)[10];

十三、有關HTTP、TCP/UDP

OSI(Open System Interconnection)模型定制的七層標準模型分別是:
物理層:物理層是OSI參考模型的最低層,它利用傳輸介質為數(shù)據鏈路層提供物理連接。它主要關心的是通過物理鏈路從一個節(jié)點向另一個節(jié)點傳送比特流,物理鏈路可能是銅線、衛(wèi)星、微波或其他的通訊媒介。它關心的問題有:多少伏電壓代表1?多少伏電壓代表0?時鐘速率是多少?采用全雙工還是半雙工傳輸?總的來說物理層關心的是鏈路的機械、電氣、功能和規(guī)程特性。主要有: 以太網 · 調制解調器 · 電力線通信(PLC) · SONET/SDH · G.709 · 光導纖維 · 同軸電纜 · 雙絞線等

數(shù)據鏈路層:數(shù)據鏈路層是為網絡層提供服務的,解決兩個相鄰結點之間的通信問題,傳送的協(xié)議數(shù)據單元稱為 數(shù)據幀。只要協(xié)議有:Wi-Fi( IEEE 802.11) · WiMAX( IEEE 802.16) ·ATM · DTM · 令牌環(huán) · 以太網 ·FDDI · 幀中繼 · GPRS · EVDO ·HSPA · HDLC · PPP · L2TP ·PPTP · ISDN·STP 等

網絡層:網絡層是為傳輸層提供服務的,傳送的協(xié)議數(shù)據單元稱為 數(shù)據包或分組。該層的主要作用是解決如何使數(shù)據包通過各結點傳送的問題,即通過 路徑選擇算法( 路由)將數(shù)據包送到目的地。另外,為避免 通信子網中出現(xiàn)過多的數(shù)據包而造成 網絡阻塞,需要對流入的數(shù)據包數(shù)量進行控制( 擁塞控制)。當數(shù)據包要跨越多個通信子網才能到達目的地時,還要解決網際互連的問題。IP (IPv4 · IPv6) · ICMP· ICMPv6·IGMP ·IS-IS · IPsec · ARP · RARP等

傳輸層:TCP · UDP · TLS · DCCP · SCTP · RSVP · OSPF 等

會話層:會話層主要功能是管理和協(xié)調不同主機上各種進程之間的通信(對話),即負責建立、管理和終止應用程序之間的會話。會話層得名的原因是它很類似于兩個實體間的會話概念。例如,一個交互的用戶會話以登錄到計算機開始,以注銷結束。

表示層:表示層處理流經結點的 數(shù)據編碼的表示方式問題,以保證一個系統(tǒng)應用層發(fā)出的信息可被另一系統(tǒng)的應用層讀出。如果必要,該層可提供一種標準表示形式,用于將計算機內部的多種 數(shù)據表示格式轉換成 網絡通信中采用的標準表示形式。數(shù)據壓縮和加密也是表示層可提供的轉換功能之一。


OSTE.png

四次揮手:
所謂四次揮手(Four-Way Wavehand)即終止TCP連接,就是指斷開一個TCP連接時,需要客戶端和服務端總共發(fā)送4個包以確認連接的斷開。在socket編程中,這一過程由客戶端或服務端任一方執(zhí)行close來觸發(fā)。
(1)第一次揮手:客戶端發(fā)送一個FIN包,用來關閉客戶端和服務器的數(shù)據傳送,客戶端進入FIN_WAIT_1狀態(tài)。
(2)第二次揮手:服務端收到FIN包后,發(fā)送一個ACK給客戶端,服務端進入CLOSE_WAIT狀態(tài)。
(3)第三次揮手:服務端發(fā)送一個FIN包,用來關閉服務端到客服端的數(shù)據傳送,服務端進入LAST_ACK狀態(tài)。
(4)第四次揮手:客戶端收到FIN包,客戶端進入TIME_WAIT狀態(tài),接著發(fā)送一個ACK包給服務端,服務端進入關閉狀態(tài),完成四次揮手。

實際上socket是對TCP/IP協(xié)議的封裝,Socket本身并不是協(xié)議,而是一個調用接口(API),通過Socket,才能使用TCP/IP協(xié)議。
總結:
1.HTTP是應用層協(xié)議,定義的是傳輸數(shù)據的內容以及格式的規(guī)范。
2.TCP是底層通訊協(xié)議,定義的是數(shù)據傳輸和連接方式的規(guī)范。
3.Socket可以支持不同的傳輸層協(xié)議(TCP/UDP),當使用TCP協(xié)議進行連接時,該Socket連接就是一個TCP連接,Socket是發(fā)動機,提供了網絡通信的能力
Socket是傳輸控制層接口,WebSocket是應用層協(xié)議。
一個完成的HTTP協(xié)議要包含三個部分: 請求行、請求頭、請求體
請求行:主要包含請求方法、請求路徑、HTTP協(xié)議版本
請求頭:主要包含了對客戶端環(huán)境的描述,客戶端請求的主機地址信息。
請求體:客戶端發(fā)給服務器的具體數(shù)據,比如文件/數(shù)據

HTTP協(xié)議規(guī)定:1個完整的HTTP響應中包含以下內容:
狀態(tài)行:包含了HTTP協(xié)議版本、狀態(tài)嗎、狀態(tài)碼對應的英文名稱HTTP/1.1 200 OK
響應頭:包含了對服務器的描述,對返回數(shù)據的描述。
實體內容:服務器返回給客戶端的具體數(shù)據(圖片/html/文件...)
HTTP協(xié)議定義了很多方法對應不同的資源操作,其中最常用的是GET 和 POST 方法.
 GET、POST、OPTIONS、HEAD、PUT、DELETE、TRACE、CONNECT、PATCH
  增:PUT、刪:DELETE、改:POST、查:GET
GET 和 POST 都是和服務器提交參數(shù)/通訊的一種方式。GET 參數(shù)不能太長<1024B POST 沒有限制<4G
GET 不能上傳文件, POST 可以上傳文件

(1)JSON底層原理:遍歷字符串中的字符,最終根據格式規(guī)定的特殊字符,比如{}、[]、:等進行區(qū)分,{}號表示字典,[]號表示數(shù)組,:號是字典的鍵和值的分水嶺,最終仍是將JSON轉化為字典,只不過字典中的值可能是“字典、數(shù)組或者字符串而已”。

在網絡請求中如何提高性能

17.App網絡層有哪然優(yōu)化策路?.png

十四、數(shù)據持久化存儲方案有哪些?

1)plist 文件(屬性列表)
2)preference(偏好設置)

  1. NSKeyedArchiver(歸檔)
    4)SQlite
  2. CoreData

十五、計時器 NSTimer 循環(huán)引用

  1. 選擇合適的時機手動釋放timer(該方法并不太合理)
  • (void)viewDidDisappear:(BOOL)animated {
    [super viewDidDisappear:animated];
    [self.timer invalidate];
    self.timer=nil;
    }
  1. timer使用block方式添加Target-Action
  2. 給self添加中間件proxy
    考慮到循環(huán)引用的原因,改方案就是需要打破這些相互引用關系,因此添加一個中間件,弱引用self,同時timer引用了中間件,這樣通過弱引用來解決了相互引用,如圖:
    使用NSProxy解決NSTimer、CADisplayLink等循環(huán)引用
#import <Foundation/Foundation.h>

@interface YHProxy : NSProxy
+ (instancetype)proxyWithTarget:(id)target;
@property (weak, nonatomic) id target;
@end

#import "YHProxy.h"

@implementation YHProxy

+ (instancetype)proxyWithTarget:(id)target
{
    // NSProxy對象不需要調用init,因為它本來就沒有init方法
    YHProxy *proxy = [YHProxy alloc];
    proxy.target = target;
    return proxy;
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel
{
    return [self.target methodSignatureForSelector:sel];
}

- (void)forwardInvocation:(NSInvocation *)invocation
{
    [invocation invokeWithTarget:self.target];
}
@end
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:[YHProxy proxyWithTarget:self] selector:@selector(timerTest) userInfo:nil repeats:YES];

十六、如何減小一個應用程序占用存儲空間?

檢查程序 去掉多余的 xib。iOS App Store 相關因素作為提交到 App Store 中 app 里的可執(zhí)行文件是被加過密的。加密的副作用是可執(zhí)行 文件的壓縮效果沒有之前的好了。Build Settings 編譯選項,將 build setting 中的 Optimization Level 設置為 Fastest, Smallest [-Os]; 將 build setting 中 的 Strip Debug Symbols During Copy 設 置 為 YES(COPY_PHASE_STRIP = YES),這樣可以減小編譯出二進制文件的尺
寸。Target 針對較少的 CPUs 對程序指定的特定 CPU 類型做優(yōu)化處理, 以生成相對于的可執(zhí)行文件。不同的硬件,將運行不同的可執(zhí)行代碼。 雖然這樣優(yōu)化后的程序,只能針對某些設備運行,但是這大大減小可 執(zhí)行程序的大小。要想只設定特定類型的CPUs,可以修改build setting 中的 Architectures,將其從 Standard $(ARCHS_STANDARD)修改為你希 望支持的列表中對應的特定類型 CPU。有效的 CPU 名稱列在 Valid Architectures (VALID_ARCHS) build setting 中。請不要修改 Valid Architectures 設置項,最好由 Xcode 管理。盡量使用 8-bit 圖片。使 用 8-bit 的 PNG 圖片,比 32-bit 的圖片能減少 4 倍的壓縮率。由于 8-bit 的圖片支持最多 256 種不同的顏色,所以 8-bit 的圖片一般只應該用 于一小部分的顏色圖片。例如灰度圖片最好使用 8-bit。

十七、KVO、KVC

KVO

Pasted Graphic.png

Apple 使用了 1Sa 混寫(1sa-Sw1zz11ng) 來交現(xiàn) XVO.png

KVC

2咖果有 Seae月KWC特M自粉 1R 8CGRRTsancaveralarertl 月有發(fā)新海國w 數(shù)認標有烤編海期S.png

十八、怎么理解oc面向對象,oc有多重繼承嗎?

面向對象的三大特性:封裝、繼承和多態(tài)。
封裝就是把數(shù)據及其操作的實現(xiàn)細節(jié)隱藏起來,對外公開接口(即“合理隱藏,合理暴露”)。這樣可以保證數(shù)據安全性,外部不能隨便訪問類的成員變量,只能通過(setter,getter)方法訪問。
繼承的作用是抽取出了重復的代碼,建立了類和類之間的聯(lián)系
多態(tài):由繼承演變而來,父類指針指向子類對象,即同一類型的對象調用同一方法,表現(xiàn)出不同行為
oc不能多繼承,但是可以通過其他方法實現(xiàn)“多繼承”效果
方法一:采用組合的模式來代替繼承模式。
方法二:
雖然OC在語法上禁止類使用多繼承,但是在協(xié)議的遵守上卻允許使用多繼承。所以可以用協(xié)議來實現(xiàn)多繼承。但是協(xié)議只能提供接口,而沒有提供實現(xiàn)方式,如果只是想多繼承基類的接口,那么遵守多協(xié)議無疑是最好的方法,而既需要多繼承接口,又要多繼承其實現(xiàn),那么協(xié)議是無能為力了。多協(xié)議遵守比較簡單,具體的實現(xiàn)方式這里就不講了
方法三:給NSObject添加category
因為NSObject是所有類的父類,給NSObject添加類別就相當于給所有的類添加了這些方法,所有的類都可以使用這些方法。

十九、項目中有用到哪些組件化

1、常?的三種方案
1.1 URL Scheme

  •   使 URL 處理本地的跳轉
    
  •   通過中間層進?注冊 & 調? (load方法里把被調用者注冊到中間層)
    
  •   注冊表?需使用反射
      非懶加載 / 注冊表的維護 / 參數(shù)
    
    代表是MGJRouter
    MGJRouter就一個單例類,使用前需要通過注冊組件,調用方通過URL調用服務方頁面,通過路由表的映射關系進行關聯(lián),調用方可以傳入復 雜的參數(shù)、對象
    實現(xiàn)原理:
    App啟動時實例化各組件模塊,然后這些組件向ModuleManager注冊Url,有些時候不需要實例化,使用class注冊
    當組件A需要調用組件B時,向ModuleManager傳遞URL,參數(shù)跟隨URL以GET方式傳遞,類似openURL。然后由ModuleManager負責調度組件B,最后完成任務。

1.2 Target - Action

  •   抽離業(yè)務邏輯
    
  •   通過中間層進行調?
    
  •   中間層使? runtime 反射
    
  •   中間層代碼優(yōu)化
    

CTMediator
原理是通過oc的runtime、category特性動態(tài)獲取模塊,例如通過NSClassFromString獲取類并創(chuàng)建實例,通過performSelector + NSInvocation動態(tài)調用方法。
實現(xiàn)原理:
1、利用分類為路由添加新接口,在接口中通過字符串獲取對應的類
2、通過runtime創(chuàng)建實例,動態(tài)調用實例的方法

1.3 Protocol - Class 匹配

  •   增加 Protocol Wrapper層 (中間件先注冊Protocol和Class對應關系,將protocol和對應的類進行字典匹配)
    
  •   中間件返回 Protocol 對應的 Class,然后動態(tài)創(chuàng)建實例
    
  •   解決硬編碼的問題
    
  • BeeHive
  • protocol比較典型的三方框架就是阿里的BeeHive。BeeHive借鑒了Spring Service、Apache DSO的架構理念,采用AOP+擴展App生命周期API形式,將業(yè)務功能、基礎功能模塊以模塊方式以解決大型應用中的復雜問題,并讓模塊之間以Service形式調用,將復雜問題切分,以AOP方式模塊化服務。
  • BeeHive 核心思想
  • 1、各個模塊間調用從直接調用對應模塊,變成調用Service的形式,避免了直接依賴。
  • 2、App生命周期的分發(fā),將耦合在AppDelegate中邏輯拆分,每個模塊以微應用的形式獨立存在。

二十、id和NSObject*的區(qū)別

1、id是objc_object的結構體指針,定義是typedef struct objc_object id,所有的oc對象都可以用id指向,而且在編譯階段不作類型檢查。id對象調用這個對象存在的方法在編譯階段都不會報錯,但是調用不存在的方法會。
2、NSObject指向的必須是NSObject的子類,調用的方法也必須是NSObject子類的方法,否則必須作強制的類型轉換。
3、不是所有的oc對象都是NSObject的子類,比如說有一些繼承自NSProxy,NSObject*可指向的對象是id的子集。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容