iOS 基礎

一、字符串經常使用方法

字符串截取程序員

NSString *strSub = [str substringFormIndex:2];算法

NSString *strSubT = [str substringToIndex:2];編程

NSString *strSubR = [str substringWithRange:range];json

字符串替換windows

NSString *newStr = [str stringByReplacingOccurencesOfString:@"ll" withString:@"al"];
設計模式

編碼,把UTF8編碼的字符串編碼成URL中可用的字符串
數組

url_cn = [url_cn stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
緩存

字符串轉數組安全

NSArray *array = [str componentsSeparatedByString:@","];--分隔符bash

數組轉字符串

NSString *str = [array componentsJoinedByString:@","];--分隔符

字符串轉字典

NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
    
NSError *err;
    
NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:jsonData
                         
                              options:NSJSONReadingMutableContainers
                         
                                                         error:&err];複製代碼

字典轉字符串

NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dic options:NSJSONWritingPrettyPrinted error:&parseError];複製代碼

二、數組

數組替換

[_dataSource replaceObjectAtIndex:1 withObject:recentArray];

數組倒序

NSArray *array = @[@1, @20, @3, @10, @2];//排序後到新數組裏
NSArray *sortedArray = [array sortedArrayUsingComparator:^NSComparisonResult(NSNumber* obj1, NSNumber* obj2) {
 if ([obj1 intValue] > [obj2 intValue]) {
     return NSOrderedDescending;
 } else { 
     return NSOrderedAscending;
 } 
}];複製代碼

三、淺談iOS開發中方法延遲執行的集中方式

1》performSelector方法

- (void)performSelector:(SEL)aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay;複製代碼

2》NSTimer定時器

+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;複製代碼

3》NSThread線程的sleep

+ (void)sleepForTimeInterval:(NSTimeInterval)ti;複製代碼

4》GCD

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

});複製代碼

四、寫一個完整的代理,包括生命、實現

//建立
@protocol MyDelegate
@required
-(void)eat:(NSString *)food;
@optional
-(void)run;
@end
//聲明.h
@interface person:NSObject<MyDelegate>
@end
//實現.m
@implementation person
-(void)eat:(NSString *)food{
}
-(void)run{
}
@end複製代碼

五、BAD_ACCESS在什麼狀況下出現

這種問題在開發時常常遇到,緣由是訪問了野指針,好比訪問已經釋放的對象的成員變量或者發消息、死循環等。

六、lldb(gdb)經常使用的控制檯調試命令

1》p 輸出基本類型,是打印命令,須要指定類型,是print的簡寫

p (int)[[[self view] subviews] count]複製代碼

2》po 打印對象,會調用description方法,是print-object的簡寫

po [self view]複製代碼

3》expr 能夠在調試時動態執行制定表達式,並將結果打印出來。經常使用於在調試過程當中修改變量的值。

4》bt 打印調用堆棧,是thread backtrace的簡寫,加all可打印全部的thread的堆棧

5》br l 是breakpoint list的簡寫

七、你通常是怎麼用Instruments的?

Instruments裏面工具不少,經常使用的有:

1》Time Profiler:性能分析

2》Zoombies:檢查是否訪問了殭屍對象,可是這個工具只能從上往下檢查,不智能

3》Allocations:用來檢查內存,寫算法的那批人也用這個來檢查

4》Leaks:檢查內存,看是否有內存泄漏

八、iOS經常使用的數據存儲方式有哪些?

數據存儲有四種方案:NSUserDefault、KeyChain、file、DB。 
其中File有三種方式:plist、Archive(歸檔)
DB包括:SQLite、FMDB、CoreData複製代碼

九、Runtime能夠作什麼事情

1》獲取類裏面的全部成員變量

2》爲類動態添加成員變量

3》動態改變類的方法實現

4》爲類動態添加新的方法。

十、WKWebView與UIWebView的比較替換

相比於UIWebView的優點

1》在性能、穩定性、佔用內存方面有很大提高

2》容許JavaScript的Nitro庫加載並使用(UIWebView中限制)

3》增長加載進度實行:estimatedProgress,不用再本身寫進度條了

4》支持了更多的HTML屬性。

十一、iOS常見加密方式

1》base64加密:基本原理是本來是8個bit一組表示數據,改成6個bit一組表示數據,不足的部分補零,每兩個0用一個 = 表示;用base64編碼以後,數據長度會變大,增長了大約1/3左右;可進行反向解密;編碼有個很是顯著的特色,末尾有個 = 號

2》MD5加密:把任意一個長度的字符串換成必定長度的十六進制的大整數

3》AES加密

4》RSA加密

十二、drawRect

1》咱們只能在繼承了UIView的子類中經過重寫drawRect方法來繪製圖形

2》若是須要繪製圖形的子類直接繼承自UIView,則子類的drawRect中不須要調用父類方法[super drawRect:rect];。若是子類繼承自其它繼承UIView的view類,則drawRect方法中須要調用父類方法[super drawRect:rect];

3》drawRect方法不能手動直接調用,咱們能夠經過調用其它方法來實現drawRect方法的調用。如:在子類初始化時調用- (instancetype)initWithFrame:(CGRect)frame方法,且frame不爲CGRectZero時。

4》咱們能夠調用setNeedsDisplay()方法或setNeedsDisplayInRect方法,可是該方法不會本身調用drawRect方法,而是會標記視圖,並在下一次循環更新的時候讓視圖經過drawRect來進行重繪,前提是rect不爲CGRectZero。

1三、iOS開發中的鎖

1》臨界區:指的是一塊對公共資源進行訪問的代碼,並不是是一種機制或者算法。

2》互斥鎖:是一種用於多線程編程中,防止兩條線程同時對同一個公共資源進行讀寫的機制,該目的經過將代碼切片成一個一個的臨界區而達成。

3》自旋鎖:是用於多線程同步的一種鎖,線程會反覆檢查鎖變量是否可用。因爲線程在這一過程當中保持執行,所以是一種忙等待。一旦獲取了自旋鎖,線程會一直保持該鎖,直至顯示釋放自旋鎖。自旋鎖避免了進城上下文的調度開銷,所以對於線程只會阻塞很短期的場合是有效的。

4》讀寫鎖:是計算機程序的併發控制的一種同步機制,也稱「共享-互斥鎖」、多讀者-單寫者鎖,用於解決多線程對公共資源的讀寫問題。讀操做可併發重入,寫操做是互斥的。讀寫鎖一般用互斥鎖、條件變量、信號量實現。

5》信號量:是一種更高級的同步機制,互斥鎖能夠說是semaphore在僅取值0/1的特例。信號量能夠有更多的取值空間,用來實現更加複雜的同步,而不僅僅是線程間互斥。

6》條件鎖:就是條件變量,當進城的某些資源要求不知足時就進入休眠,也就是鎖住了。當資源被分配到了,條件鎖打開,進城繼續運行。

1四、系統對象的 copy 與 mutableCopy 方法

無論是集合類對象(NSArray、NSDictionary、NSSet ... 之類的對象),仍是非集合類對象(NSString, NSNumber ... 之類的對象),接收到copy和mutableCopy消息時,都遵循如下準則:
1. copy 返回的是不可變對象(immutableObject);若是用copy返回值調用mutable對象的方法就會crash。
2. mutableCopy 返回的是可變對象(mutableObject)。

1、非集合類對象的copy與mutableCopy
  在非集合類對象中,對不可變對象進行copy操做,是指針複製,mutableCopy操做是內容複製;
  對可變對象進行copy和mutableCopy都是內容複製。用代碼簡單表示以下:
    NSString *str = @"hello word!";
    NSString *strCopy = [str copy] // 指針複製,strCopy與str的地址同樣
    NSMutableString *strMCopy = [str mutableCopy] // 內容複製,strMCopy與str的地址不同

    NSMutableString *mutableStr = [NSMutableString stringWithString: @"hello word!"];
    NSString *strCopy = [mutableStr copy] // 內容複製
    NSMutableString *strMCopy = [mutableStr mutableCopy] // 內容複製

2、集合類對象的copy與mutableCopy (同上)
  在集合類對象中,對不可變對象進行copy操做,是指針複製,mutableCopy操做是內容複製;
  對可變對象進行copy和mutableCopy都是內容複製。可是:集合對象的內容複製僅限於對象自己,對集合內的對象元素仍然是指針複製。(即單層內容複製)
    NSArray *arr = @[@[@"a", @"b"], @[@"c", @"d"];
    NSArray *copyArr = [arr copy]; // 指針複製
    NSMutableArray *mCopyArr = [arr mutableCopy]; //單層內容複製
   
    NSMutableArray *array = [NSMutableArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c",nil];
    NSArray *copyArr = [mutableArr copy]; // 單層內容複製
    NSMutableArray *mCopyArr = [mutableArr mutableCopy]; // 單層內容複製
    
【總結一句話】:
    只有對不可變對象進行copy操做是指針複製(淺複製),其它狀況都是內容複製(深複製)!複製代碼

1五、寫一個 setter 方法用於完成 @property (nonatomic, retain) NSString *name,寫一個 setter 方法用於完成 @property (nonatomic, copy) NSString *name

答:
// retain
- (void)setName:(NSString *)str {
  [str retain];
  [_name release];
  _name = str;
}
// copy
- (void)setName:(NSString *)str {
  id t = [str copy];
  [_name release];
  _name = t;
}複製代碼

1六、KVC的底層實現?

當一個對象調用setValue方法時,方法內部會作如下操做:
1). 檢查是否存在相應的key的set方法,若是存在,就調用set方法。
2). 若是set方法不存在,就會查找與key相同名稱而且帶下劃線的成員變量,若是有,則直接給成員變量屬性賦值。
3). 若是沒有找到_key,就會查找相同名稱的屬性key,若是有就直接賦值。
4). 若是尚未找到,則調用valueForUndefinedKey:和setValue:forUndefinedKey:方法。
這些方法的默認實現都是拋出異常,咱們能夠根據須要重寫它們。複製代碼

1七、你是否接觸過OC中的反射機制?簡單聊一下概念和使用

1). class反射
    經過類名的字符串形式實例化對象。
        Class class = NSClassFromString(@"student"); 
        Student *stu = [[class alloc] init];
    將類名變爲字符串。
        Class class =[Student class];
        NSString *className = NSStringFromClass(class);
2). SEL的反射
    經過方法的字符串形式實例化方法。
        SEL selector = NSSelectorFromString(@"setName");  
        [stu performSelector:selector withObject:@"Mike"];
    將方法變成字符串。
        NSStringFromSelector(@selector*(setName:));複製代碼

1八、調用方法有兩種方式

1). 直接經過方法名來調用。[person show];
2). 間接的經過SEL數據來調用 SEL aaa = @selector(show); [person performSelector:aaa];  複製代碼

1九、iOS的沙盒目錄結構是怎樣的?

沙盒結構:
1). Application:存放程序源文件,上架前通過數字簽名,上架後不可修改。
2). Documents:經常使用目錄,iCloud備份目錄,存放數據。(這裏不能存緩存文件,不然上架不被經過)
3). Library:
        Caches:存放體積大又不須要備份的數據。(經常使用的緩存路徑)
        Preference:設置目錄,iCloud會備份設置信息。
4). tmp:存放臨時文件,不會被備份,並且這個文件下的數據有可能隨時被清除的可能。複製代碼

20、什麼是 TCP / UDP ?

TCP:傳輸控制協議。
UDP:用戶數據協議。

TCP 是面向鏈接的,創建鏈接須要經歷三次握手,是可靠的傳輸層協議。
UDP 是面向無鏈接的,數據傳輸是不可靠的,它只管發,無論收不收穫得。
簡單的說,TCP注重數據安全,而UDP數據傳輸快點,但安全性通常。複製代碼

2一、通訊底層原理(OSI七層模型)

OSI採用了分層的結構化技術,共分七層:
    物理層、數據鏈路層、網絡層、傳輸層、會話層、表示層、應用層。複製代碼

2二、block的實質是什麼?有幾種block?分別是怎麼產生的?

block本質上是一個OC對象,他內部也有一個isa指針。block是封裝了函數調用以及函數調用環境的OC對象。

一共有三種block,分別是全局的、棧上的、堆上的

__NSGlobalBlock__直到程序結束纔會被回收

__NSStackBlock__類型block存放在棧中,咱們直到棧中的內存由系統自動分配和釋放,做用域執行完畢以後就會被當即釋放

__NSMallocBlock__是在平時編碼過程當中最經常使用到的。存放在堆中須要咱們本身進行內存管理。


__block用於解決block內部不能修改auto變量值的問題,__block不能修飾靜態變量(static) 和全局變量

詳解

2三、不借用第三個變量,如何交換兩個變量的值?要求手動寫出交換過程

方法一:
a = a + b;
b = a - b;      // b = (a +b)-b,即 b = a
a = a - b;      // a =  (a+b)-a
方法二:
a = a - b;
b = a + b;     // b = (a-b)+b,即b=a
a = b - a;      // a = a - (a-b)複製代碼

2四、設計模式有哪些

1》觀察者模式:KVO是典型的觀察者模式,觀察某個屬性的改變,改變時會通知觀察者

2》委託模式:代理+協議的組合,實現1對1的反向傳值操做

3》單利模式:經過static關鍵詞,聲明全局變量,在整個進程運行期間只會被賦值一次

2五、@property的本質是什麼,有哪些屬性關鍵字

1》@property的本質是實例變量+存取方法。

2》原子性與非原子性

讀寫權限

內存管理語義 assign strong weak copy

方法名 getter setter

不經常使用的 nonnull nullable等

2六、何時使用weak關鍵字,相比assign有什麼區別

1》在ARC中,有可能出現循環引用的時候使用weak,好比代理,block;自身已經對他進行一次強引用,沒有必要再強引用一次,好比IBOutlot,由於父控件的subviews數組已經對他有一個強引用

2》weak代表該屬性定義了一種「非擁有關係」。在該屬性所指的對象銷燬時,屬性值會自動清空(nil)。

3》assign能夠用於非OC對象,weak必須用於OC對象。

2七、怎麼使用copy關鍵字

1》NSString,NSArray,NSDictionary等常用copy關鍵字,由於他們有對應的可變類型。若是使用strong關鍵字,那麼這個屬性就有可能指向一個可變對象,若是這個可變對象修改了,那麼會影響該屬性。若是可變對象使用了copy關鍵字,那麼這個可變對象作增刪改的時候,系統會由於找不到對應的程序而崩潰。由於copy複製的是一個不可變對象,不可變對象是不能進行增刪改的操做的。

2》block也常用copy關鍵字。block使用copy關鍵字是從MRC留下來的傳統,方法內部的block是在棧區的,使用copy能夠把他放到堆區。在ARC中寫不寫都行,使用copy或者strong效果都是同樣的。

2八、如何讓本身的類用copy修飾符?如何重寫帶copy關鍵字的setter方法?

1》該類須要聽從NSCopying協議

2》實現NSCopying的協議: - (id)copyWithZone:(NSZone *)zone;

2九、@synthesize 和 @dynamic 分別有什麼做用?

若是@synthesize和@dynamic都沒寫,那麼默認的就是@synthesize var = _var ;@synthesize的語義是若是你沒有手動實現setter和getter方法,那麼編譯器會自動爲你加上這兩個方法。@dynamic告訴編譯器,屬性的setter和getter方法油用戶本身實現,不自動生成。

30、常見的OC的數據類型有哪些,和C的基本數據類型有什麼區別?如:NSInteger和int

OC的數據類型有NSString,NSArray,NSData等等,這些都是class,建立後即是對象,而C語言的基本數據類型是int,只是有必定字節的內存空間,用於存放數值。NSinteger是基本數據類型,不是NSNumber的子類,固然也不是NSObject的子類。NSInteger是基本數據類型int或者long的別名。他的區別在於,NSInteger會根據系統是32位仍是64位來決定自己是int仍是long。

3一、OC如何對內存管理的,說說你的見解和解決方案?

OC的內存管理模式主要有三種:ARC(自動內存計數)、手動內存計數、內存池

1》自動內存計數(ARC):由Xcode自動在APP編譯階段,在代碼中添加內存管理代碼

2》手動內存計數(MRC):遵循內存誰申請,誰釋放;誰添加,誰釋放的原則

3》內存釋放池:把須要釋放的內存統一放在一個池子裏面,當池子被抽乾後,池子中全部的內存空間也會被自動釋放。內存池的釋放操做分爲自動和手動,自動釋放受runloop機制影響。

3二、weak和strong的區別

1》strong指針可以保持對象的生命,一個對象只要有strong指針指向他,那麼他就不會被釋放,相反的,若是沒有strong指針指向他,那麼他就會被自動釋放。默認的局部變量都是強指針,存放在堆裏面

2》weak型的指針變量仍然能夠是一個對象,可是不屬於對象的擁有者。即當對象被銷燬的時候,這個weak指針也就自動指向nil。

3三、block在ARC和MRC中的區別

如何判斷當前文件是MRC仍是ARC:dealloc方法中可否調用super,只有MRC才能調用super;可否用retain、release,若是能夠就是MRC。

MRC沒有strong、weak,局部變量對象就是至關於基本數據類型;MRC給成員變量賦值必定要用set方法,不能直接訪問下劃線成員屬性賦值。

總之,只要block不引用外部變量,block放在全局區。

MRC 管理block:只要block引用外部變量,block放在棧區,block只能使用copy不能使用retain,用retain,block仍是在棧裏面

ARC管理block:只要block引用外部變量,block就放在堆區,block使用copy,儘可能不要使用strong。

3四、KVO、NSNotifaction、delegate、block的區別

1》KVO是觀察者模式,通常搭配KVC使用,經過KVO能夠監測一個值得變化,是一對多的關係,一個值的變化會通知全部的觀察者。

2》NSNotifaction是通知,一對多,在某些狀況下,KVO和NSNotifaction是同樣的,都是狀態變化以後告知對方。不一樣的是,NSNotifaction須要被觀察者先主動發出通知,而後觀察者註冊監聽後再來進行響應,比KVO多了發送通知這一步,可是其優勢是監聽不侷限與屬性的變化,還能夠對多種多樣的狀態進行監聽,監聽範圍廣,使用也更靈活。

3》delegate是代理,就是把本身不想作的事情交給別人去作,不須要關心中間須要作的事情,只要調用delegate就能夠了,由其餘類完成所須要的動做,因此是一對一的。

4》block是delegate的另外一種形式,是函數式編程的一種形式,使用場景和delegate同樣,相比delegate更爲靈活,並且實現也更直觀。

5》KVO通常的使用場景是數據,需求是數據變化。delegate通常的使用場景是行爲,須要別人幫忙作一件事情。NSNotifaction通常是進行全局通知,只須要發出通知就能夠,不關心你有沒有接受到通知。delegate是強關聯,就是委託和代理雙方都知道。

3五、談談UITablebView的優化

1》正確的複用cell

2》設計統一規格的cell

3》提早計算並緩存好高度,由於heightForRowAtIndexPath是調用最頻繁的方法

4》異步繪製,遇到複雜頁面,遇到性能瓶頸時,可能就是突破口

5》滑動時按需加載,這個在大量圖片展現,網絡加載的時候很管用

6》減小子視圖的層級關係

7》不要動態的add或者remove子控件,最好在初始化的時候就添加完,而後經過hidden來控制是否顯示。

3六、OC中堆和棧的區別

管理方式:棧是編譯器自動管理,堆的釋放工做由程序員空

棧:在Windows下,棧是向低地址擴展的數據結構,是一塊連續的內存區域。這句話的意思是棧頂的地址和棧的最大容量是系統預先設計好的。在windows 下,棧的大小是2M(也有的說是1M),若是申請的空間超過棧的剩餘空間是,將提示overFlow,所以,能從棧得到的空間較小。

堆:堆是向高笛子擴展的數據結構,是不連續的內存區域。堆得大小受限於計算機系統中有效的虛擬內存,因而可知,堆得到空間比較靈活,也比較大。

碎片問題:對於堆來說,頻繁的new/delete勢必會形成內存空間的不連續,從而形成大量的碎片,使程序效率下降。對於棧來說,則不會存在這個問題,由於棧是先進後出的隊列,他們是如此的一一對應,以致於永遠都不可能有一個內存塊從棧中間彈出分配方式:堆都是動態分配的,沒有靜態分配的堆。

棧有2種分配方式:靜態分配和動態分配。靜態分配是編譯器完成的,好比局部變量的分配。動態分配由alloca函數進行分配,可是棧的動態分配和堆是不一樣的,他的動態分配是由編譯器進行釋放,無需咱們手工實現。分配效率:棧是機器系統提供的數據結構,計算機會在底層對棧提供支持:分配專門的寄存器存放棧的地址,壓棧出棧都有專門的指令執行,這就決定了棧的效率比較高。堆則是C/C++函數庫提供的,它的機制是很複雜的。

3七、分類和擴展

分類裏面有類名,方法列表,協議列表,可是沒有屬性列表,因此原則上來講,分類只能添加方法,不能添加屬性的。固然,添加屬性也能夠,只要不去調用他。由於添加的屬性沒有get和set方法,雖然咱們能夠用runtime去動態的添加set和get方法,可是調用屬性的時候仍是不會經過的,由於他沒有實例變量。

分類裏邊添加的方法,即便不實現也是不會報錯的,由於分類是在運行時添加到類裏邊去的。可是擴展添加的方法必需要實現,由於擴展是在編譯時添加進去的。

分類裏邊添加的方法若是和原有類中的方法重名,則會優先調用分類中的方法,所以儘可能不要覆蓋原有類中的方法。

擴展添加的屬性默認是私有的,擴展沒有獨立的實現部分,也就是說,擴展中所聲明的方法必須依託對應的類的實現部分來實現。

3八、atomic的實現機制:爲何不能保證絕對的線程安全

用atomic生成的set和get方法會進行加鎖操做,這個鎖僅僅保證了存取方法的線程安全,並不是真正意義上的線程安全,由於線程安全還有除了讀寫以外的其餘操做(好比:當一個線程正在進行讀取方法的操做時,同時又有一個線程在進行release操做,可能會直接出現crash)

atomic 更耗費資源,速度要慢,若是沒有多線程之間的通信,儘可能仍是使用nonatomic。

舉例:當幾個線層同時調用同一屬性的讀取方法時,會get到一個完整的值,可是get的值不可控

線程1 調用get

線程2 調用set

線程3 調用set

這3個線程同時執行,線程1 會get到一個值,可是get到的值不可控,有多是線程2 線程3 以前的原始值,也有多是線程2 線層3 set以後的值

nonatomic 生成的讀取方法沒有加鎖,線程不安全,可是更快,當同一個線程同時訪問同一個屬性時,會出現沒法預料的結果。

3九、被weak修飾的對象在被釋放的時候會發生什麼?是如何實現的?知道sidetable嗎?裏面的結構能夠畫出來嗎

被weak修飾的對象在釋放時會被置爲nil,不一樣於assign。

runtime 維護了一個weak 表,用於存儲指向某個對象的全部weak 指針。weak表實際上是一個hash 表,key是所指對象的地址,value是weak指針的地址數組。

1》初始化時,runtime會調用objc_initWeak函數,初始化一個新的weak指針指向對象的地址

2》添加引用時,objc_initWeak函數會調用objc_storeWeak函數,objc_storeWeak的做用是更顯指針指向,建立對應的弱引用表。

3》釋放時,調用clearDeallocating函數。clearDeallocating函數首先根據對象地址獲取全部weak指針地址的數組,而後遍歷這個數組把其中的數據置爲nil,最後把這個entry從weak表中刪除,最後清理對象的記錄。

sideTable

struct SideTable {
    // 保證原子操做的自旋鎖
    spinlock_t slock;
    // 引用計數的 hash 表
    RefcountMap refcnts;
    // weak 引用全局 hash 表
    weak_table_t weak_table;
}

struct weak_table_t {
    // 保存了全部指向指定對象的 weak 指針
    weak_entry_t *weak_entries;
    // 存儲空間
    size_t    num_entries;
    // 參與判斷引用計數輔助量
    uintptr_t mask;
    // hash key 最大偏移值
    uintptr_t max_hash_displacement;
};
複製代碼


40、關聯對象有什麼應用,系統如何關聯對象?其被釋放的指針須要手動將全部的關聯對象的指針置空嗎?

AssociationsManager裏面是由一個靜態AssociationsHashMap來存儲全部的關聯對象的。這至關於把全部對象的關聯對象都存在一個全局map裏面。而map的key是這個對象的指針地址(任意兩個不一樣對象的指針地址必定是不一樣的),而這個map的value又是另一個AssociationsHashMap,裏面保存了關聯對象的kv對。

在obj dealloc 的時候會調用object_dispose,檢查有無關聯對象,有的話就_object_remove_assocations刪除

www.jianshu.com/p/e9582e7df…

4一、KVO的底層實現?如何取消系統默認的KVO並手動觸發(給KVO的觸發設定條件:改變的值符合某個條件時再觸發KVO)?

當觀察某對象A時,KVO機制動態建立一個對象A當前的子類,並未這個新的子類重寫了被觀察屬性keyPath 的 setter 方法。setter 方法隨後負責通知觀察對象屬性的改變情況。

Apple 使用了 isa 混寫(isa-swizzling)來實現 KVO 。當觀察對象A時,KVO機制動態建立一個新的名爲:NSKVONotifying_A 的新類,該類繼承自對象A的本類,且 KVO 爲 NSKVONotifying_A 重寫觀察屬性的 setter 方法,setter 方法會負責在調用原 setter 方法以前和以後,通知全部觀察對象屬性值的更改狀況。

使用方法,可實現取消系統kvo,本身觸發,也就可控。

+(BOOL)automaticallyNotifiesObserversForKey:(NSString *)key{
    if ([key isEqualToString:@"name"]) {
        return NO;
    }else{
        return [super automaticallyNotifiesObserversForKey:key];
    }
}
-(void)setName:(NSString *)name{
    
    if (_name!=name) {
        
        [self willChangeValueForKey:@"name"];
        _name=name;
        [self didChangeValueForKey:@"name"];
    }
      
}複製代碼

4二、class_ro_t和class_rw_t的區別

objc類中的屬性、方法還有遵循的協議等消息都保存在class_rw_t中;

其中還有一個指向常量的的指針ro,其中存儲到了當前類在編譯器就已經肯定的屬性、方法以及聽從的協議。

4三、iOS中內省的幾個方法?class方法和object_getClass有什麼區別?

內省方法:

判斷對象類型:

-(BOOL) isKindOfClass:判斷是不是這個類或者這個類的子類的實例

-(BOOL) isMemberOfClass:判斷是不是這個類的實例

判斷對象or類是否有這個方法

-(BOOL) respondsToSelector:判斷實例是否有這樣方法

+(BOOL) instancesRespondToSelector: 判斷類是否有這個方法

object_getClass:得到的是isa的指向

self.class:當self是實例對象的時候,返回的是類對象,不然返回自身。類方法class,返回的是self,因此當查找meta class,須要類對象調用object_getClass方法。

4四、一個int變量被_block修飾與否的區別

沒有修飾,被block捕獲,是值拷貝。

使用_block修飾,會生成一個結構體,複製int的引用地址,達到修改數據。

4五、爲何block在外部使用_weak修飾的同時須要在內部使用__strong修飾

涉及到捕獲的時候該變量是存在的,在執行block的時候可能被捕獲對象釋放了。

4六、Runloop的做用是什麼?他的內部工做機制瞭解嗎

Runloop的做用是用來管理線程的,當線程的Runloop開啓後,線程就會在執行任務後,處於休眠狀態,隨時等待接受新的任務,而不是退出。

只有主線程的Runloop是默認開啓的,因此線程在開啓後,纔會一直運行,不會退出。其餘線程的Runloop若是須要開啓,就須要手動開啓。

在Runloop內部有一個判斷循環的條件,若是知足條件,就一直循環,線程獲得喚醒事件被喚醒,事件處理完畢之後,回到睡眠狀態,等待下次喚醒。

4七、哪些場景能夠觸發離屏渲染

設置了一下屬性時,都會觸發離屏渲染:

1》shouldRasterize(光柵化)

2》masks(遮罩)

3》shadows(陰影)

4》edge antialiasing(抗鋸齒)

5》group opacity(不透明)

6》複雜形狀設置圓角等
7》漸變

4八、block

  • 當沒有外部變量時,block爲__NSMallocBlock,它由開發者建立,存儲在堆內存上。
  • 當有__weak修飾時block爲__NSStackBlock,存儲在棧區。
  • 當block有參數時(捕獲了外部變量時)block爲__NSGlobalBlock,存儲在全局區。
  • block的本質是一個結構體。
  • 在block內部使用外部指針且會造循環引用狀況下,須要使用__weak修飾外部指針
  • 在block內部若是調用了延時函數仍是用弱指針會取不到該指針,由於已經被銷燬了,須要在block內部再將弱指針從新強引用一下。
  • 若是須要在block內部改變外部棧區變量的話,須要用__block修飾外部變量。
  • 4九、delegate和block的使用比較

    1》共同點:block和delegate的方法均可以理解成回調函數,當某件事情發生的時候執行一段代碼片斷。

    2》block優勢:是一種輕量級的回調,可以直接訪問上下文,使用塊的地方和塊的實現地方在同一個地方,使得代碼組織更加連貫。

    3》delegate:相對來講是重量級的回調,由於方法的生命和實現分離開來,代碼的連貫性不是很好,代理不少時候都須要存儲一些臨時數據。代理的回調函數能夠是一組多個函數,在不一樣的時機調用不一樣的回調函數。

    4》怎麼選擇:當回調函數多餘3個的時候,採用代理比較好;使用代碼塊容易形成循環引用,代理不會出現該問題;其餘狀況下優先考慮代碼塊。

    50、UIViewController的生命週期

    1》[ViewController initWithCoder:][ViewController initWithNibName:Bundle]:首先從歸檔文件中加載UIViewController對象。即便是純代碼,也會把nil做爲參數傳給後者。

    2》[UIView awakeFromNib]: 做爲第一個方法的助手,方法處理一些額外的設置。

    3》[ViewController loadView]:建立或加載一個view並把它賦值給UIViewControllerview屬性。

    - [ViewController viewDidLoad]: 此時整個 視圖層次(view hierarchy)已經放到內存中,能夠移除一些視圖,修改約束,加載數據等。

    4》[ViewController viewWillAppear:]: 視圖加載完成,並即將顯示在屏幕上。還沒設置動畫,能夠改變當前屏幕方向或狀態欄的風格等。

    5》[ViewController viewWillLayoutSubviews]即將開始子視圖位置佈局

    6》[ViewController viewDidLayoutSubviews]用於通知視圖的位置佈局已經完成

    7》[ViewController viewDidAppear:]:視圖已經展現在屏幕上,能夠對視圖作一些關於展現效果方面的修改。

    8》[ViewController viewWillDisappear:]:視圖即將消失

    9》[ViewController viewDidDisappear:]:視圖已經消失

    10》[ViewController dealloc:]:視圖銷燬的時候調用

    5一、AppDelegate的幾個方法

    1》當程序第一次運行而且將要顯示窗口的時候執行該方法

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

    2》程序進入後臺的時候須要先執行程序取消活躍的方法

    - (void)applicationWillResignActive:(UIApplication *)application

    3》當程序進入後臺的時候

    - (void)applicationDidEnterBackground:(UIApplication *)application

    4》當程序將要進入前臺的時候

    - (void)applicationWillEnterForeground:(UIApplication *)application

    5》當程序變得活躍的時候

    - (void)applicationDidBecomeActive:(UIApplication *)application

    6》當程序將要退出的時候

    - (void)applicationWillTerminate:(UIApplication *)application

    若是程序在後臺能夠運行,則上面的方法會被替換成applicationDidEnterBackground

    5二、反射是什麼?能夠舉出幾個應用場景嗎

    在計算機科學中,反射是指計算機程序在運行時(Runtime)能夠訪問、檢測和修改它自己狀態或行爲的一種能力。用比喻來講,反射就是程序在運行的時候可以「觀察」而且改變本身的而行爲。

    要注意術語「反射」和「內省」的關係:內省機制僅指程序在運行時對自身信息的檢測;反射機制不只包括要能在運行時對程序自身信息進行檢測,還要求程序能進一步根據這些信息改變程序狀態或結構。

    一個重點是改變,一個重點是檢測。

    好比經過類名,生成類 Class * tempClass = NSClassFromString(str);
    爲類增長方法等。

    5三、有哪些場景是NSOperation比GCD更容易實現的?(或者是NSOperation優於GCD的幾點)

    GCD是基於C的底層API,NSOperation屬於object-c類。

    相對於GCD:

    1》NSOperation擁有更多的函數可用

    2》在NSOperationQueue中,能夠創建各個NSOperation之間的依賴關係。

    3》有KVO,能夠檢測NSOperation是否正在執行,是否結束,是否取消

    4》NSOperationQueue能夠方便的管理開發

    5四、APP啓動優化策略?最好結合啓動流程來講(main函數的執行先後都分別說一下)

    www.jianshu.com/p/a51fcabc9…

    5五、OC中建立線程的方法是什麼?若是在主線程中執行代碼,方法是什麼?

    // 建立線程的方法
    - [NSThread detachNewThreadSelector:nil toTarget:nil withObject:nil]
    - [self performSelectorInBackground:nil withObject:nil];
    - [[NSThread alloc] initWithTarget:nil selector:nil object:nil];
    - dispatch_async(dispatch_get_global_queue(0, 0), ^{});
    - [[NSOperationQueue new] addOperation:nil];
    
    // 主線程中執行代碼的方法
    - [self performSelectorOnMainThread:nil withObject:nil waitUntilDone:YES];
    - dispatch_async(dispatch_get_main_queue(), ^{});
    - [[NSOperationQueue mainQueue] addOperation:nil];
    複製代碼

    5六、用僞代碼寫一個線程安全的單例模式

    static id _instance;
    + (id)allocWithZone:(struct _NSZone *)zone {
       static dispatch_once_t onceToken;
       dispatch_once(&onceToken, ^{
           _instance = [super allocWithZone:zone];
       });
       return _instance;
    }
    
    + (instancetype)sharedData {
       static dispatch_once_t onceToken;
       dispatch_once(&onceToken, ^{
           _instance = [[self alloc] init];
       });
       return _instance;
    }
    
    - (id)copyWithZone:(NSZone *)zone {
       return _instance;
    }複製代碼

    5七、AFNetworking 底層原理分析

    AFNetworking主要是對NSURLSession和NSURLConnection(iOS9.0廢棄)的封裝,其中主要有如下類:
    1). AFHTTPRequestOperationManager:內部封裝的是 NSURLConnection, 負責發送網絡請求, 使用最多的一個類。(3.0廢棄)
    2). AFHTTPSessionManager:內部封裝是 NSURLSession, 負責發送網絡請求,使用最多的一個類。
    3). AFNetworkReachabilityManager:實時監測網絡狀態的工具類。當前的網絡環境發生改變以後,這個工具類就能夠檢測到。
    4). AFSecurityPolicy:網絡安全的工具類, 主要是針對 HTTPS 服務。
    
    5). AFURLRequestSerialization:序列化工具類,基類。上傳的數據轉換成JSON格式
        (AFJSONRequestSerializer).使用很少。
    6). AFURLResponseSerialization:反序列化工具類;基類.使用比較多:
    7). AFJSONResponseSerializer; JSON解析器,默認的解析器.
    8). AFHTTPResponseSerializer; 萬能解析器; JSON和XML以外的數據類型,直接返回二進
    制數據.對服務器返回的數據不作任何處理.
    9). AFXMLParserResponseSerializer; XML解析器;複製代碼

    5八、描述下SDWebImage裏面給UIImageView加載圖片的邏輯

    SDWebImage 中爲 UIImageView 提供了一個分類UIImageView+WebCache.h, 這個分類中有一個最經常使用的接口sd_setImageWithURL:placeholderImage:,會在真實圖片出現前會先顯示佔位圖片,當真實圖片被加載出來後再替換佔位圖片。
        
    加載圖片的過程大體以下:
        1.首先會在 SDWebImageCache 中尋找圖片是否有對應的緩存, 它會以url 做爲數據的索引先在內存中尋找是否有對應的緩存
        2.若是緩存未找到就會利用經過MD5處理過的key來繼續在磁盤中查詢對應的數據, 若是找到了, 就會把磁盤中的數據加載到內存中,並將圖片顯示出來
        3.若是在內存和磁盤緩存中都沒有找到,就會向遠程服務器發送請求,開始下載圖片
        4.下載後的圖片會加入緩存中,並寫入磁盤中
        5.整個獲取圖片的過程都是在子線程中執行,獲取到圖片後回到主線程將圖片顯示出來
        
    SDWebImage原理:
    調用類別的方法:
        1. 從內存(字典)中找圖片(當這個圖片在本次使用程序的過程當中已經被加載過),找到直接使用。
        2. 從沙盒中找(當這個圖片在以前使用程序的過程當中被加載過),找到使用,緩存到內存中。
        3. 從網絡上獲取,使用,緩存到內存,緩存到沙盒。複製代碼

    5九、HTTPS和HTTP的區別

    一、https協議須要到ca申請證書,通常免費證書較少,於是須要必定費用。
    二、http是超文本傳輸協議,信息是明文傳輸,https則是具備安全性的ssl加密傳輸協議。
    三、http和https使用的是徹底不一樣的鏈接方式,用的端口也不同,前者是80,後者是443。
    四、http的鏈接很簡單,是無狀態的;HTTPS協議是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網絡協議,比http協議安全。

    60、iOS中imageNamed 和 imageWithContentOfFile的區別

     使用imageNamed:加載圖片
    1. 加載到內存中後,會一直停留在內存中,不會隨着對象銷燬而銷燬
    2. 加載進圖片後,佔用的內存歸系統管理,咱們沒法管理
    3. 相同的圖片,圖片不會從新加載
    4. 加載到內存中後,佔據內存空間較大
    使用 imageWithContentOfFile:加載圖片
    1. 加載到內存中後,佔據內存空間比較小
    2. 相同的圖片會被重複加載到內存中
    3. 對象銷燬的時候,加載到內存中得圖片會被一塊兒銷燬
    結論:若是圖片較小,頻繁使用的圖片,使用imageNamed來加載圖片(如按鈕圖片、主頁圖片、展位圖)

    若是圖片較大,使用次數少,建議使用imageWithContentOfFile來加載圖片(相冊、版本新特性)

    6一、爲何assign不用用於修飾對象?

    首先咱們須要明確,對象的內存通常被分配到堆上,基本數據類型和oc數據類型的內存通常被分配在棧上。

    若是用assign修飾對象,當對象被釋放後,指針的地址仍是存在的,也就是說指針並無被置爲nil,從而形成了野指針。由於對象是分配在堆上的,堆上的內存由程序員分配釋放。而由於指針沒有被置爲nil,若是後續的內存分配中,恰好分配到了這塊內存,就會形成崩潰。

    而assign修飾基本數據類型或oc數據類型,由於基本數據類型是分配在棧上的,由系統分配和釋放,因此不會形成野指針。

    6二、id類型的指針爲何能夠指向任意類型?

    id是一個比較靈活的對象指針,而且是一個指向任何一個繼承自Object(或者NSObject)類的對象,而在cocoa的開發環境裏,NSObject是全部類的根類,因此id能夠指向任何一個cocoa的合法對象。

    typedef struct objc_object {
     Class isa;
    } *id;複製代碼

    id和NSObject的區別:

    NSObject是一個靜態數據類型,id是一個動態數據類型,默認狀況下全部的數據類型都是靜態數據類型。

    6三、load和initalize

    + (void)load;
    1.對於加入運行期系統的類以及分類,一定會調用此方法,且僅調用一次。
    2.iOS會在應用程序啓動的時候調用load方法,在main函數以前調用
    3.執行子類的load方法前,會先執行全部超類的load方法,順序爲父類->子類->分類
    4.load方法不聽從繼承規則,若是類自己沒有實現load方法,那麼系統就不會調用,無論父類有沒有實現
    5.儘量的精簡load方法,由於整個應用程序在執行load方法時會阻塞,即,程序會阻塞知道全部的load方法執行完畢,纔會繼續
    7.load方法中最經常使用的就是方法交換 method swizzling複製代碼
    + (void)initialize;
    1.在首次使用該類以前有運行期系統(非人爲)調用,且僅調用一次
    2.惰性調用,只有當程序使用相關類時,纔會調用
    3.若是類未實現initialize方法,而其超類實現了,那麼會運行超類的實現代碼,且會運行兩次,且第一次打印出來是父類,第二次打印出來是子類
    4.initialize遵循繼承規則
    5.初始化子類的時候會優先初始化父類,而後調用父類的initialize方法,而子類沒有覆寫initialize方法,所以會再次調用父類方法
    複製代碼

    6四、深刻解構objc_msgSend函數的實現

    一般狀況下每一個OC對象的最開始處都有一個隱藏的數據成員isa,isa保存有類的描述信息(包含方法數組列表和緩存)

    struct objc_class {    
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;
    
    #if !__OBJC2__ 
    
    Class _Nullable super_class                              
    OBJC2_UNAVAILABLE;    
    const char * _Nonnull name                               OBJC2_UNAVAILABLE;    
    long version                                             OBJC2_UNAVAILABLE;    
    long info                                                OBJC2_UNAVAILABLE;    
    long instance_size                                       OBJC2_UNAVAILABLE;    
    struct objc_ivar_list * _Nullable ivars                  OBJC2_UNAVAILABLE;    
    struct objc_method_list * _Nullable * _Nullable methodLists                    OBJC2_UNAVAILABLE;    
    struct objc_cache * _Nonnull cache                       OBJC2_UNAVAILABLE;    
    struct objc_protocol_list * _Nullable protocols          
    OBJC2_UNAVAILABLE;#endif
    } OBJC2_UNAVAILABLE;複製代碼

    經過isa指針,去objc_cache裏面查找是否有緩存的方法,若是有,則直接調用,若是沒有則去objc_method_list裏面去尋找對應的方法的實現,若是再找不到,就進入到消息轉發的階段了。

    6五、AFNetworking3.0後爲何再也不須要常駐線程?

    AF2.x爲何須要常駐線程:

    AF2.x 首先須要在子線程去start connection,請求發送成功後,所在的子線程須要保活以保證正常接收到NSURLConnectionDelegate回調方法。若是每來一個請求就開闢一條線程,而且保活線程,這樣開銷就太大了。因此只須要保活一條固定的線程,在這個線程裏發起請求,接收回調。

    AF3.x爲何不須要常駐線程?

    NSURLSession發起的請求,再也不須要在當前線程進行代理方法的回調,能夠指定回調的delegateQueue,這樣咱們就不用爲了等待代理回調方法而苦苦保活線程了。


    若有問題,請各位大神指出,謝謝!

    相關文章
    相關標籤/搜索