iOS 面試題

一泥张、網(wǎng)絡(luò)層

1.簡(jiǎn)介 TCP 和 UDP 區(qū)別,他們位于哪一層种蘸?
TCP和UDP同屬于OSI七層網(wǎng)絡(luò)模型的第四層傳輸層墓赴。
TCP是傳輸控制協(xié)議,特點(diǎn):面向連接的劈彪,可靠的竣蹦,點(diǎn)對(duì)點(diǎn)的通信,傳輸數(shù)據(jù)多沧奴,速度較慢痘括。
UDP是用戶(hù)數(shù)據(jù)報(bào)協(xié)議,特點(diǎn):非連接滔吠,不可靠纲菌,多對(duì)多的通信,傳輸數(shù)據(jù)少疮绷,速度快翰舌。
2.描述TCP 協(xié)議三次握手,四次釋放的過(guò)程冬骚。
-------------三次握手----------
(1)第一次握手:建立連接時(shí)椅贱,客戶(hù)端A發(fā)送SYN包(SYN=j)到服務(wù)器B懂算,并進(jìn)入SYN_SEND狀態(tài),等待服務(wù)器B確認(rèn)庇麦。
(2)第二次握手:服務(wù)器B收到SYN包计技,必須確認(rèn)客戶(hù)A的SYN(ACK=j+1),同時(shí)自己也發(fā)送一個(gè)SYN包(SYN=k)山橄,即SYN+ACK包垮媒,此時(shí)服務(wù)器B進(jìn)入SYN_RECV狀態(tài)。
(3)第三次握手:客戶(hù)端A收到服務(wù)器B的SYN+ACK包航棱,向服務(wù)器B發(fā)送確認(rèn)包ACK(ACK=k+1)睡雇,此包發(fā)送完畢,客戶(hù)端A和服務(wù)器B進(jìn)入ESTABLISHED狀態(tài)饮醇,完成三次握手它抱。
-------------四次揮手----------
(1)客戶(hù)端A發(fā)送一個(gè)FIN,用來(lái)關(guān)閉客戶(hù)A到服務(wù)器B的數(shù)據(jù)傳送驳阎。
(2)服務(wù)器B收到這個(gè)FIN抗愁,它發(fā)回一個(gè)ACK,確認(rèn)序號(hào)為收到的序號(hào)加1呵晚。和SYN一樣蜘腌,一個(gè)FIN將占用一個(gè)序號(hào)。
(3)服務(wù)器B關(guān)閉與客戶(hù)端A的連接饵隙,發(fā)送一個(gè)FIN給客戶(hù)端A撮珠。
(4)客戶(hù)端A發(fā)回ACK報(bào)文確認(rèn),并將確認(rèn)序號(hào)設(shè)置為收到序號(hào)加1金矛。
3.HTTP 請(qǐng)求中的 GET 和 POST 的區(qū)別芯急,Session 和 Cookie 的區(qū)別。
GET驶俊,請(qǐng)求數(shù)據(jù)會(huì)附加在URL之后娶耍,請(qǐng)求的數(shù)據(jù)會(huì)暴露在地址欄,傳輸數(shù)據(jù)會(huì)受到URL長(zhǎng)度的限制饼酿,安全性較低榕酒,一般用于獲取服務(wù)器數(shù)據(jù)。
POST故俐,請(qǐng)求數(shù)據(jù)放到請(qǐng)求體中想鹰,理論上是不會(huì)受限制的,但是實(shí)際上各個(gè)服務(wù)器會(huì)規(guī)定對(duì)POST提交數(shù)據(jù)大小進(jìn)行限制药版,安全性低辑舷。 上傳請(qǐng)求均可以。
cookie數(shù)據(jù)存放在客戶(hù)的瀏覽器上槽片,不安全何缓,存放其他信息肢础。
session數(shù)據(jù)放在服務(wù)器上,相對(duì)安全歌殃,存放登錄信息乔妈。
4.TCP 協(xié)議是如何進(jìn)行流量控制,擁塞控制的氓皱?
滑動(dòng)窗口機(jī)制實(shí)現(xiàn)

二、操作系統(tǒng)與編譯

1.堆和棧的區(qū)別

  • 按管理方式勃刨,
    對(duì)于棧來(lái)講波材,是由系統(tǒng)編譯器自動(dòng)管理,不需要程序員手動(dòng)管理身隐;
    對(duì)于堆來(lái)講廷区,釋放工作由程序員手動(dòng)管理,不及時(shí)回收容易產(chǎn)生內(nèi)存泄露贾铝。
  • 按分配方式分隙轻,
    棧有兩種分配方式:靜態(tài)分配和動(dòng)態(tài)分配;
    堆是動(dòng)態(tài)分配和回收內(nèi)存的垢揩,沒(méi)有靜態(tài)分配的堆玖绿。
    按申請(qǐng)大小,
    椚蓿空間小斑匪,堆空間大。
  • 按數(shù)據(jù)存儲(chǔ)锋勺,
    棧一般存儲(chǔ)基本類(lèi)型對(duì)象的地址蚀瘸,
    堆一般存放對(duì)象本身,block的copy等庶橱。

三贮勃、內(nèi)存管理

1.內(nèi)存管理修飾關(guān)鍵字
nonatomic: 非原子的,禁止多線(xiàn)程苏章,變量保護(hù)寂嘉,提高性能.
assign:普通賦值,常用于基本數(shù)據(jù)類(lèi)型布近,也可以用來(lái)修飾對(duì)象垫释,但是,被assign修飾的對(duì)象在釋放后撑瞧,指針的地址還是存在的棵譬,也就是說(shuō)指針并沒(méi)有被置為nil,成為野指針预伺。也可以修飾非OC對(duì)象 比如C數(shù)據(jù)類(lèi)型(int, float,double, char, 等等)
retain:獲得對(duì)象所有權(quán)订咸,引用計(jì)數(shù)+1
weak:弱引用曼尊,相當(dāng)于MRC的assign,當(dāng)指向的對(duì)象銷(xiāo)毀后脏嚷,weak會(huì)將變量置為nil骆撇,防止野指針,用于代理父叙,UI控件神郊。
strong:強(qiáng)引用,相當(dāng)于MRC的retain趾唱,
copy:賦值方式 將新值復(fù)制一份賦覆蓋原值,用于NSString涌乳、block等類(lèi)型。不可變對(duì)象使用copy相當(dāng)于retain甜癞,只是引用計(jì)數(shù)+1
注意:strong和weak只能修飾對(duì)象
2.用@property聲明的NSString(或NSArray夕晓,NSDictionary)經(jīng)常使用copy關(guān)鍵字,為什么悠咱?如果改用strong關(guān)鍵字蒸辆,可能造成什么問(wèn)題?
(1) 因?yàn)楦割?lèi)指針可以指向子類(lèi)對(duì)象,使用copy的目的是為了讓本對(duì)象的屬性不受外界影響,使用copy無(wú)論給我傳入是一個(gè)可變對(duì)象還是不可對(duì)象,我本身持有的就是一個(gè)不可變的副本.
(2) 如果我們使用是strong,那么這個(gè)屬性就有可能指向一個(gè)可變對(duì)象,如果這個(gè)可變對(duì)象在外部被修改了,那么會(huì)影響該屬性.
3._ block和 _weak的區(qū)別
__block:在ARC和MRC下都可用析既,可修飾對(duì)象躬贡,也可以修飾基本數(shù)據(jù)類(lèi)型。__block對(duì)象可以在block被重新賦值渡贾,__weak不可以逗宜。
__weak:只在ARC中使用,只能修飾對(duì)象空骚,不能修飾基本數(shù)據(jù)類(lèi)型纺讲,在ARC下,要避免block出現(xiàn)循環(huán)引用囤屹,經(jīng)常會(huì):__weak typedof(self) weakSelf = self;
4.野指針
(1)出現(xiàn)場(chǎng)景

1.訪問(wèn)一個(gè)僵尸對(duì)象熬甚,訪問(wèn)僵尸對(duì)象的成員變量或者向其發(fā)消息
2.死循環(huán)

(2)如何調(diào)試

開(kāi)啟僵尸對(duì)象調(diào)試:Edit Scheme--Enable Zombie Objects

四、設(shè)計(jì)模式(對(duì)象通信和交互)

1.代理
delegate實(shí)質(zhì)上是一種回調(diào)肋坚,主要用于兩個(gè)對(duì)象之間的通信交互乡括,優(yōu)點(diǎn)是解耦合,注重回調(diào)結(jié)果智厌。比如:tableViewDelegate诲泌,但需要聲明協(xié)議,定義代理屬性铣鹏,設(shè)置代理敷扫,步驟較多。
2.通知
通知特點(diǎn)一對(duì)多诚卸,通信對(duì)象之間不需要建立聯(lián)系葵第,只負(fù)責(zé)發(fā)送通知不關(guān)心結(jié)果绘迁,缺點(diǎn),代碼可讀性差卒密,一般步驟 注冊(cè)通知中心-發(fā)通知-接通知執(zhí)行方法-移除通知缀台。
3.KVO
鍵值觀察,用來(lái)監(jiān)聽(tīng)對(duì)象的屬性值的變化哮奇,步驟跟通知類(lèi)似膛腐。

鍵值觀察通知依賴(lài)于NSObject 的兩個(gè)方法: willChangeValueForKey: 和 didChangevlueForKey:;
在一個(gè)被觀察屬性發(fā)生改變之前屏镊, willChangeValueForKey: 一定會(huì)被調(diào)用依疼,這就會(huì)記錄舊的值。
而當(dāng)改變發(fā)生后而芥,didChangeValueForKey: 會(huì)被調(diào)用,繼而 observeValueForKey:ofObject:change:context:
也會(huì)被調(diào)用膀值。
  • KVO 底層實(shí)現(xiàn)原理--runtime
    當(dāng)觀察者對(duì)象 A 棍丐,KVO 機(jī)制動(dòng)態(tài)的創(chuàng)建一個(gè)對(duì)象 A 當(dāng)前的子類(lèi),并為這個(gè)新的子類(lèi)重寫(xiě)了被觀察者的屬性 keyPath 的 setter 方法沧踏。隨后 setter 方法就負(fù)責(zé)通知觀察對(duì)象屬性的改變狀況歌逢。
  • 如何手動(dòng)觸發(fā)一個(gè)value的KVO
    自動(dòng)觸發(fā)的場(chǎng)景:在注冊(cè)KVO之前設(shè)置一個(gè)初始值,注冊(cè)之后翘狱,設(shè)置一個(gè)不一樣的值秘案,就可以觸發(fā)了。
    手動(dòng)觸發(fā)演示:
@property (nonatomic, strong) NSDate *now;
- (void)viewDidLoad{ 
  [super viewDidLoad];
 [self willChangeValueForKey:@"now"]; // “手動(dòng)觸發(fā)self.now的KVO”潦匈,必寫(xiě)阱高。
 [self didChangeValueForKey:@"now"]; // “手動(dòng)觸發(fā)self.now的KVO”,必寫(xiě)茬缩。
}

4.單利
確保一個(gè)類(lèi)只有一個(gè)對(duì)象赤惊,所有類(lèi)都可以訪問(wèn)和設(shè)置單利對(duì)象中的屬性數(shù)據(jù),通常采用懶加載創(chuàng)建凰锡∥粗郏可以節(jié)約性能。
5.block(下面單獨(dú)講)

五掂为、數(shù)據(jù)持久----

iOS 之 FMDB裕膀、CoreData、Plist勇哗、NSUserDefault詳解
1.屬性列表
涉及的類(lèi):NSUserDefaults,一般[NSUserDefaults standardUserDefaults]
示例:

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];//單例
[defaults setValue:@"yfyfyfyfyfyfyfy"forKey:@"username"];
[defaults setValue:@"123"forKey:@"password"];```
//注意:UserDefaults設(shè)置數(shù)據(jù)時(shí)昼扛,不是立即寫(xiě)入,而是根據(jù)時(shí)間戳定時(shí)地把緩存中的數(shù)據(jù)寫(xiě)入本地磁盤(pán)智绸。所以調(diào)用了set方法之后數(shù)據(jù)有可能還沒(méi)有寫(xiě)入磁盤(pán)應(yīng)用程序就終止了野揪。出現(xiàn)以上問(wèn)題访忿,可以通過(guò)調(diào)用synchornize方法強(qiáng)制寫(xiě)入到文件中
```[defaults synchronize];```

//讀取
NSString *name = [defaults valueForKey:@"username"];
NSString *pwd = [defaults valueForKey:@"password"];```
2.對(duì)象歸檔
要使用對(duì)象歸檔,對(duì)象必須實(shí)現(xiàn)NSCoding協(xié)議.大部分Object C對(duì)象都符合NSCoding協(xié)議,也可以在自定義對(duì)象中實(shí)現(xiàn)NSCoding協(xié)議,要實(shí)現(xiàn)NSCoding協(xié)議,實(shí)現(xiàn)兩個(gè)方法
--進(jìn)行編碼--

- (void)encodeWithCoder:(NSCoder*)coder
{
//[super encodeWithCode:coder];如果父類(lèi)也遵守了NSCoding協(xié)議,確保繼承的實(shí)例變
量也能被編碼,即也能被歸檔
[coder encodeObject:self.nameforKey:@"name"];
[coder encodeInteger:self.ageforKey:@"age"];
[coder encodeObject:self.genderforKey:@"gender"];
}```
--進(jìn)行解碼--
  • (id)initWithCoder:(NSCoder*)aDecoder
    {
    //self = [super initWithCoder:aDecoder];確保繼承的實(shí)例變量也能
    被解碼斯稳,即也能被恢復(fù)
    self= [super init];
    if(self) {
    self.name= [aDecoder decodeObjectForKey:@"name"];
    self.gender= [aDecoder decodeObjectForKey:@"gender"];
    self.age= [aDecoder decodeIntegerForKey:@"age"];
    }
    return self;
    }
    @end```
    3.SQLite3
    (1)常用 SQLite 語(yǔ)句 及 SQLite3 的使用
/*
使用數(shù)據(jù)庫(kù)的準(zhǔn)備工作
1.導(dǎo)入libsqlite3.dylib靜態(tài)庫(kù)
2.導(dǎo)入sqlite3.h頭文件         #import <sqlite3.h>

使用數(shù)據(jù)庫(kù)注意事項(xiàng)
1.使用數(shù)據(jù)庫(kù)時(shí),要保證數(shù)據(jù)庫(kù)文件存在
2.使用數(shù)據(jù)庫(kù)前,要保證數(shù)據(jù)庫(kù)是打開(kāi)狀態(tài)
3.使用數(shù)據(jù)庫(kù)后,要關(guān)閉數(shù)據(jù)庫(kù)
 */
#import "ViewController.h"
#import <sqlite3.h>
@interface ViewController ()
{
    sqlite3 *_db;
}
@property (retain, nonatomic) IBOutlet UITextField *nameText;
@property (retain, nonatomic) IBOutlet UITextField *ageTextField;

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    NSLog(@"%@",NSHomeDirectory());
}

- (void)dealloc {
    [_nameText release];
    [_ageTextField release];
    [super dealloc];
}
#pragma mark -- 創(chuàng)建數(shù)據(jù)庫(kù)文件并打開(kāi)數(shù)據(jù)庫(kù)
-(BOOL)openDatabase
{
    //數(shù)據(jù)庫(kù)文件路徑
    NSString *filePath = [NSHomeDirectory()stringByAppendingPathComponent:@"Documents/student.sqlite"];
    //UTF8String把oc的字符串轉(zhuǎn)化成c的字符串
    const char *filename = [filePath UTF8String];
    // sqlite3_open 打開(kāi)數(shù)據(jù)庫(kù)的方法; 如果有數(shù)據(jù)庫(kù)文件就直接打開(kāi),如果沒(méi)有數(shù)據(jù)庫(kù)文件系統(tǒng)會(huì)自動(dòng)創(chuàng)建一個(gè)數(shù)據(jù)庫(kù)文件,并打開(kāi)
    //參數(shù)1.數(shù)據(jù)庫(kù)文件的路徑 2.數(shù)據(jù)庫(kù)對(duì)象,要打開(kāi)的數(shù)據(jù)庫(kù)
    //返回值表示操作的狀態(tài)碼
    int result = sqlite3_open(filename, &_db);
    if (result == SQLITE_OK)
    {
        NSLog(@"數(shù)據(jù)庫(kù)打開(kāi)成功");
        return YES;
    }
    else
    {
        NSLog(@"數(shù)據(jù)庫(kù)打開(kāi)失敗");
        //sqlite3_close 關(guān)閉數(shù)據(jù)庫(kù)的方法
        sqlite3_close(_db);
        return NO;
    }
}
#pragma mark --創(chuàng)建表
- (IBAction)createTable:(id)sender
{
    //1.打開(kāi)數(shù)據(jù)庫(kù)
    if (![self openDatabase])
    {
        return;
    }
    //2.創(chuàng)建表
    NSString *str = @"CREATE TABLE IF NOT EXISTS student (student_id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT , age INTEGER)";
    char *error = nil;
    //sqlite3_exec對(duì)數(shù)據(jù)庫(kù)的操作:創(chuàng)建表,增刪改,都是用這個(gè)方法
    //參數(shù) 1.數(shù)據(jù)庫(kù)對(duì)象 2.sql語(yǔ)句 3.回調(diào)函數(shù)nil 4.回調(diào)函數(shù)的參數(shù)nil
    if (sqlite3_exec(_db, [str UTF8String], nil, nil, &error)==SQLITE_OK)
    {
        NSLog(@"創(chuàng)建表成功");
    }
    else
    {
        NSLog(@"創(chuàng)建表失敗:%s",error);
    }
    //3.關(guān)閉數(shù)據(jù)庫(kù)
    sqlite3_close(_db);
}
#pragma mark -- 添加數(shù)據(jù)
- (IBAction)insertInto:(id)sender
{
    //1.打開(kāi)數(shù)據(jù)庫(kù)2.執(zhí)行增刪改查的操作3.關(guān)閉數(shù)據(jù)庫(kù)
    if (![self openDatabase])
    {
        return;
    }
    NSString *str = [NSString stringWithFormat:@"insert into student (name , age) values ('%@',%d)",_nameText.text,_ageTextField.text.intValue];
    char *error = nil;
    if (sqlite3_exec(_db, [str UTF8String], nil, nil, &error)==SQLITE_OK)
    {
        NSLog(@"插入數(shù)據(jù)成功");
    }
    else
    {
        NSLog(@"插入數(shù)據(jù)失敗:%s",error);
    }
    sqlite3_close(_db);
}
#pragma mark -- 刪除數(shù)據(jù)
- (IBAction)delete:(id)sender
{
    if (![self openDatabase])
    {
        return;
    }
    NSString *str =@"delete from student where student_id = 6";
    char *error = nil;
    if (sqlite3_exec(_db, [str UTF8String], nil, nil, &error)==SQLITE_OK)
    {
        NSLog(@"刪除成功");
    }
    else
    {
        NSLog(@"刪除失敗:%s",error);
    }
    sqlite3_close(_db);
}
#pragma mark -- 修改數(shù)據(jù)
- (IBAction)upData:(id)sender
{
    if (![self openDatabase])
    {
        return;
    }
    NSString *str = [NSString stringWithFormat:@"update student set name = '%@' where student_id =%d",@"馬云",2];
    if (sqlite3_exec(_db, [str UTF8String], nil, nil, nil)==SQLITE_OK)
    {
        NSLog(@"修改數(shù)據(jù)成功");
    }
    else
    {
        NSLog(@"修改數(shù)據(jù)失敗");
    }
    sqlite3_close(_db);
}
#pragma mark --查詢(xún)數(shù)據(jù)
- (IBAction)select:(id)sender
{
    //先打開(kāi)數(shù)據(jù)庫(kù),查詢(xún),關(guān)閉數(shù)據(jù)庫(kù)
    if (![self openDatabase])
    {
        return;
    }
    NSString *str = @"select * from student";
    //緩存區(qū)
    sqlite3_stmt *stmt = nil;
    //sqlite3_prepare 把sql語(yǔ)句放入緩存區(qū)
    //參數(shù)1.數(shù)據(jù)庫(kù)對(duì)象2.sql語(yǔ)句 3.sql語(yǔ)句的長(zhǎng)度,-1全部的sql語(yǔ)句 4.緩存區(qū) 5.剩余部分的sql語(yǔ)句
    if (sqlite3_prepare(_db, [str UTF8String], -1, &stmt, nil)==SQLITE_OK)
    {
        //sqlite3_step 單步查詢(xún)數(shù)據(jù),一次只查詢(xún)一條數(shù)據(jù)
        //SQLITE_ROW表示數(shù)據(jù)庫(kù)中還有數(shù)據(jù)繼續(xù)下一個(gè)查詢(xún)
        //SQLITE_DONE 表示數(shù)據(jù)查詢(xún)完畢
        while (sqlite3_step(stmt) == SQLITE_ROW)
        {
            //sqlite3_column_text 查詢(xún)字符串的方法
            //參數(shù)1.緩存區(qū) 2.字段所在的列號(hào)
            char *cname = (char *)sqlite3_column_text(stmt, 1);
            int age = sqlite3_column_int(stmt, 2);
            //stringWithUTF8String 把c的字符串轉(zhuǎn)化成oc的字符串
            NSString *name = [NSString stringWithUTF8String:cname];
            NSLog(@"%@---%d",name,age);
        }
        //查詢(xún)結(jié)束,釋放緩存區(qū)
        sqlite3_finalize(stmt);
    }
    sqlite3_close(_db);
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [self.view endEditing:YES];
}
@end

4.FMDB
建議不直接操作SQLite庫(kù),而是采用一些開(kāi)源的第三方庫(kù)來(lái)進(jìn)行操作挣惰。比如:FMDB:https://github.com/ccgus/fmdb.git

FMDB有三個(gè)主要的類(lèi):
FMDatabase,一個(gè)FMDatabase對(duì)象就代表一個(gè)單獨(dú)的SQLite數(shù)據(jù)庫(kù)卧斟,用來(lái)執(zhí)行SQL語(yǔ)句。
FMResultSet憎茂,使用FMDatabase執(zhí)行查詢(xún)后的結(jié)果集珍语。
FMDatabaseQueue,用于在多線(xiàn)程中執(zhí)行多個(gè)查詢(xún)或更新竖幔,它是線(xiàn)程安全的板乙。

5.Core Data
(1)Core Data本質(zhì)上是對(duì)SQLite的封裝,但是它不需要編寫(xiě)任何SQL語(yǔ)句拳氢。
(2)要使用Core Data募逞,需要在Xcode中的數(shù)據(jù)模型編輯器中設(shè)計(jì)好各個(gè)實(shí)體以及定義好他們的屬性和關(guān)系。之后馋评,通過(guò)操作這些對(duì)象放接,結(jié)合Core Data完成數(shù)據(jù)的持久化。

六留特、OC關(guān)鍵字解釋?zhuān)裕?/h1>

七纠脾、Block詳解

1.說(shuō)說(shuō)你對(duì)block的理解
(1)block就是代碼塊,類(lèi)似于“閉包”蜕青,block的實(shí)現(xiàn)是基于指針和函數(shù)指針.
(2)默認(rèn)情況下block是存儲(chǔ)在棧中的苟蹈,如果對(duì)block進(jìn)行一個(gè)copy操作,block會(huì)轉(zhuǎn)移到堆中市咆。
(3)block底層基于C語(yǔ)言汉操,執(zhí)行效率高---(多核心CPU可直接處理Block指令)
2.block 3種類(lèi)型

1、 _NSConcreteStackBlock 蒙兰,棧塊磷瘤,如果一個(gè)block引用了外部變量,那它就是一個(gè)棧塊搜变。但是它不會(huì)持有外部對(duì)象采缚;
2、_NSConcreteGlobalBlock挠他,全局塊扳抽,如果一個(gè)block沒(méi)有引用外部變量,它就是全局塊;
3贸呢、_NSConcreteMallocBlock镰烧,堆塊,如果一個(gè)block被copy了楞陷,那么它就是堆塊怔鳖。

3.循環(huán)引用
因?yàn)閎lock會(huì)給內(nèi)部的強(qiáng)指針對(duì)象進(jìn)行一次強(qiáng)引用,比如常見(jiàn)的傳入block中的self進(jìn)行強(qiáng)引用,下面是解釋?zhuān)?/p>

A對(duì)象持有B固蛾,那么B的retain count 為1结执,而此時(shí)A因?yàn)楸黄渌兞?持有,所有A的retain Count為1艾凯,而B(niǎo)又要引用A献幔,那么A的retain 
count又要加一,這樣等到持有A的那個(gè)對(duì)象釋放A的時(shí)候趾诗,就算A
的retain count減一蜡感,但還是為1,所以無(wú)法釋放恃泪,而因?yàn)锳無(wú)法釋
放铸敏,導(dǎo)致B也無(wú)法成功釋放。```
如果方法中的一些參數(shù)是 成員變量悟泵,那么可以造成循環(huán)引用,如 GCD 闪水、NSNotificationCenter,比如 GCD 內(nèi)部如果引用了 self糕非,而且 GCD 的參數(shù)是 成員變量,則要考慮到循環(huán)引用示例:

GCD
__weak typeof(self) weakSelf = self;
dispatch_group_async(_operationsGroup, _operationsQueue, ^{
[weakSelf doSomething];
[weakSelf doSomethingElse];
} );
通知
__weak typeof(self) weakSelf = self;
_observer = [[NSNotificationCenter defaultCenter]
addObserverForName:@"testKey"
object:nil
queue:nil
usingBlock:^(NSNotification *note){
[weakSelf dismissModalViewControllerAnimated:YES];
}];

解決方法:

__weak typeof(self) weakSelf = self;

**注意:block對(duì)于參數(shù)形式傳進(jìn)來(lái)的對(duì)象球榆,不會(huì)強(qiáng)引用朽肥。**
系統(tǒng)的某些block api(如UIView的block版本寫(xiě)動(dòng)畫(huà)時(shí)),不用考慮循環(huán)引用問(wèn)題持钉。當(dāng) block 本身不被 self 持有衡招,而被別的對(duì)象持有,同時(shí)不產(chǎn)生循環(huán)引用的時(shí)候每强,就不需要使用 weak self 了始腾。

//UIView 的某個(gè)負(fù)責(zé)動(dòng)畫(huà)的對(duì)象持有了 block,block 持有了 self
//因?yàn)?self 并不持有 block空执,所以就沒(méi)有循環(huán)引用產(chǎn)生浪箭,因?yàn)榫筒恍枰褂?weak self 了。
[UIView animateWithDuration:duration animations:^{
[self.superview layoutIfNeeded];
}];
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
self.someProperty = xyz;
}];
[[NSNotificationCenter defaultCenter] addObserverForName:@"someNotification"
object:nil
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification * notification) {
self.someProperty = xyz;
}];

**思考:有沒(méi)有這樣一個(gè)需求場(chǎng)景辨绊,block會(huì)產(chǎn)生循環(huán)引用奶栖,但是業(yè)務(wù)又需要你不能使用 weak self? 如果有,請(qǐng)舉一個(gè)例子并且解釋這種情況下如何解決循環(huán)引用問(wèn)題。**

>比如說(shuō)block是一個(gè)post請(qǐng)求的回調(diào)宣鄙,這個(gè)block被self持有袍镀,業(yè)務(wù)需求需要回調(diào)后調(diào)用self的一個(gè)方法,必須調(diào)用冻晤,這個(gè)時(shí)候得保證block調(diào)用前self不被釋放苇羡,就不能weak化self奥喻,就有循環(huán)引用贯钩。解決方法應(yīng)該是block回調(diào)里調(diào)用完這個(gè)方法后執(zhí)行下self.block=nil打破循環(huán)鏈就好.


#八、多線(xiàn)程(重點(diǎn)說(shuō)GCD隅很,F(xiàn)IFO)
- **隊(duì)列**

GCD 3種隊(duì)列類(lèi)型
1.串行隊(duì)列温数,一般用dispatch_queue_create绣硝,并指定隊(duì)列類(lèi)型DISPATCH_QUEUE_SERIAL;
2.并行隊(duì)列撑刺,一般指的就是全局隊(duì)列鹉胖,調(diào)用dispatch_get_global_queue函數(shù)傳入優(yōu)先級(jí)
來(lái)訪問(wèn)隊(duì)列。當(dāng)然也可以用dispatch_queue_create够傍,并指定隊(duì)列類(lèi)型DISPATCH_QUEUE_
CONCURRENT甫菠,來(lái)自己創(chuàng)建一個(gè)并發(fā)隊(duì)列。
3.主隊(duì)列冕屯,調(diào)用dispatch_get_main_queue()寂诱,

- **任務(wù)**

同步:使用dispatch_sync將任務(wù)加入隊(duì)列。將同步任務(wù)加入串行隊(duì)列安聘,會(huì)順序執(zhí)行痰洒,一般不
這樣做并且在一個(gè)任務(wù)未結(jié)束時(shí)調(diào)起其它同步任務(wù)會(huì)死鎖。將同步任務(wù)加入并行隊(duì)列浴韭,會(huì)順序執(zhí)
行丘喻,但是也沒(méi)什么意義。
異步:使用dispatch_async將任務(wù)加入隊(duì)列念颈。將異步任務(wù)加入串行隊(duì)列泉粉,會(huì)順序執(zhí)行,并且不
會(huì)出現(xiàn)死鎖問(wèn)題榴芳。將異步任務(wù)加入并行隊(duì)列嗡靡,會(huì)并行執(zhí)行多個(gè)任務(wù),這也是我們最常用的一種
方式翠语。

**1.Object C中創(chuàng)建線(xiàn)程的方法是什么?如果在主線(xiàn)程中執(zhí)行代碼,方法是什么?如果想延時(shí)執(zhí)行代碼,方法又是什么?**
線(xiàn)程創(chuàng)建有三種方法:使用NSThread創(chuàng)建叽躯、使用GCD的dispatch、使用子類(lèi)化的NSOperation,然后將其加入NSOperationQueue;
在主線(xiàn)程執(zhí)行代碼肌括,方法是

performSelectorOnMainThread

如果想延時(shí)執(zhí)行代碼可以用

performSelector:onThread:withObject: afterDelay:

或者使用GCD的函數(shù):

dispatch_after(dispatch_time(DISPATCH_TIME_NOW,(int64_t)(2.0*
NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// 2秒后異步執(zhí)行這里的代碼...
});

**2.GCD優(yōu)點(diǎn)**
(1)GCD自動(dòng)利用更多的CPU內(nèi)核
(2)GCD會(huì)自動(dòng)管理線(xiàn)程的生命周期
(3)使用簡(jiǎn)單 任務(wù)放到隊(duì)列中点骑。
(4)dispatch_queue是線(xiàn)程安全的酣难,可以隨意添加任務(wù)。
**3.GCD常用函數(shù)**
(1)dispatch_async 

dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(globalQueue, ^{
// 一個(gè)異步的任務(wù)黑滴,例如網(wǎng)絡(luò)請(qǐng)求憨募,耗時(shí)的文件操作等等
...
dispatch_async(dispatch_get_main_queue(), ^{
// UI刷新
...
});
});
應(yīng)用場(chǎng)景:這種用法非常常見(jiàn),比如開(kāi)啟一個(gè)異步的網(wǎng)絡(luò)請(qǐng)求袁辈,待數(shù)據(jù)返回后返回主隊(duì)列刷新UI菜谣;
又比如請(qǐng)求圖片,待圖片返回刷新UI等等晚缩。

(2)dispatch_after

dispatch_queue_t queue= dispatch_get_main_queue();
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), queue, ^{
// 在queue里面延遲執(zhí)行的一段代碼
...
});
應(yīng)用場(chǎng)景:這為我們提供了一個(gè)簡(jiǎn)單的延遲執(zhí)行的方式尾膊,比如在view加載結(jié)束延遲執(zhí)行一個(gè)動(dòng)畫(huà)。

(3)dispatch_once

static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// 只執(zhí)行一次的任務(wù)
...
});
應(yīng)用場(chǎng)景:可以使用其創(chuàng)建一個(gè)單例荞彼,也可以做一些其他只執(zhí)行一次的代碼冈敛,比如做一個(gè)只能點(diǎn)一
次的button。

(4)dispatch_group

//創(chuàng)建隊(duì)列組
dispatch_group_t group = dispatch_group_create();
//獲取全局并發(fā)隊(duì)列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//往隊(duì)列組中添加耗時(shí)操作
dispatch_group_async(group, queue, ^{
// 異步任務(wù)1
});

dispatch_group_async(group, queue, ^{
// 異步任務(wù)2
});

// 等待group中多個(gè)異步任務(wù)執(zhí)行完畢鸣皂,做一些事情抓谴,介紹兩種方式

// 方式1(不好,會(huì)卡住當(dāng)前線(xiàn)程)
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
...

// 方式2(比較好)
dispatch_group_notify(group, mainQueue, ^{
// 如果這里還有基于上面兩個(gè)任務(wù)的結(jié)果繼續(xù)執(zhí)行一些代碼寞缝,建議還是放到子線(xiàn)程中癌压,等
代碼執(zhí)行完畢后在回到主線(xiàn)程
// 回到主線(xiàn)程
dispatch_async(group, dispatch_get_main_queue(), ^{
// 執(zhí)行相關(guān)代碼...
});
});
應(yīng)用場(chǎng)景:上述的一種方式,可以適用于自己維護(hù)的一些異步任務(wù)的同步問(wèn)題荆陆;但是對(duì)于已經(jīng)封
裝好的一些庫(kù)滩届,比如AFNetworking等,我們不獲取其異步任務(wù)的隊(duì)列被啼,這里可以通過(guò)一種計(jì)數(shù)
的方式控制任務(wù)間同步丐吓,下面為解決單界面多接口的一種方式。

// 兩個(gè)請(qǐng)求和參數(shù)為我項(xiàng)目里面的不用在意趟据。

// 計(jì)數(shù)+1
dispatch_group_enter(group);
[JDApiService getActivityDetailWithActivityId:self.activityId Location:stockAddressId SuccessBlock:^(NSDictionary *userInfo) {
// 數(shù)據(jù)返回后一些處理
...

// 計(jì)數(shù)-1
dispatch_group_leave(group);

} FailureBlock:^(NSError *error) {
// 數(shù)據(jù)返回后一些處理
...

// 計(jì)數(shù)-1
dispatch_group_leave(group);

}];

// 計(jì)數(shù)+1
dispatch_group_enter(group);
[JDApiService getAllCommentWithActivityId:self.activityId PageSize:3 PageNum:self.commentCurrentPage SuccessBlock:^(NSDictionary *userInfo) {
// 數(shù)據(jù)返回后一些處理
...

// 計(jì)數(shù)-1
dispatch_group_leave(group);

} FailureBlock:^(NSError *error) {
// 數(shù)據(jù)返回后一些處理
...

// 計(jì)數(shù)-1
dispatch_group_leave(group);

}];

// 其實(shí)用計(jì)數(shù)的說(shuō)法可能不太對(duì),但是就這么理解吧术健。會(huì)在計(jì)數(shù)為0的時(shí)候執(zhí)行dispatch_group_notify的任務(wù)汹碱。
dispatch_group_notify(group, mainQueue, ^{
// 一般為回主隊(duì)列刷新UI
...
});

(5) dispatch_barrier_async

// dispatch_barrier_async的作用可以用一個(gè)詞概括--承上啟下,它保證此前的任務(wù)都
先于自己執(zhí)行荞估,此后的任務(wù)也遲于自己執(zhí)行咳促。本例中,任務(wù)4會(huì)在任務(wù)1勘伺、2跪腹、3都執(zhí)行完之后執(zhí)行,
而任務(wù)5飞醉、6會(huì)等待任務(wù)4執(zhí)行完后執(zhí)行冲茸。

dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{ // 任務(wù)1 ...});
dispatch_async(queue, ^{ // 任務(wù)2 ...});
dispatch_async(queue, ^{ // 任務(wù)3 ...});
dispatch_barrier_async(queue, ^{ // 任務(wù)4 ...});
dispatch_async(queue, ^{ // 任務(wù)5 ...});
dispatch_async(queue, ^{ // 任務(wù)6 ...});

應(yīng)用場(chǎng)景:和dispatch_group類(lèi)似,dispatch_barrier也是異步任務(wù)間的一種同步方式,可
以在比如文件的讀寫(xiě)操作時(shí)使用轴术,保證讀操作的準(zhǔn)確性.
注意:
1.必須是并發(fā)隊(duì)列难衰,要是串行隊(duì)列,(Global)并發(fā)隊(duì)列逗栽、串行隊(duì)列上盖袭,效果跟dispatch_(a)sync效果一樣。
2.這個(gè)函數(shù)的第一個(gè)參數(shù)queue不能是全局的并發(fā)隊(duì)列
3.作用:在它前面的任務(wù)執(zhí)行結(jié)束后它才執(zhí)行彼宠,在它后面的任務(wù)等它執(zhí)行完成后才會(huì)執(zhí)在全局

(6)dispatch_apply

// for循環(huán)做一些事情鳄虱,輸出0123456789
for (int i = 0; i < 10; i ++) {
NSLog(@"%d", i);
}

// dispatch_apply替換(當(dāng)且僅當(dāng)處理順序?qū)μ幚斫Y(jié)果無(wú)影響環(huán)境),輸出順序不定凭峡,比如1098673452
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
/*! dispatch_apply函數(shù)說(shuō)明

  • @brief dispatch_apply函數(shù)是dispatch_sync函數(shù)和Dispatch Group的關(guān)聯(lián)API
  • 該函數(shù)按指定的次數(shù)將指定的Block追加到指定的Dispatch Queue中,并等到全部的處理執(zhí)
    行結(jié)束
  • @param 10 指定重復(fù)次數(shù) 指定10次
  • @param queue 追加對(duì)象的Dispatch Queue
  • @param index 帶有參數(shù)的Block, index的作用是為了按執(zhí)行的順序區(qū)分各個(gè)Block

*/
dispatch_apply(10, queue, ^(size_t index) {
NSLog(@"%zu", index);
});
應(yīng)用場(chǎng)景:那么拙已,dispatch_apply有什么用呢,因?yàn)閐ispatch_apply并行的運(yùn)行機(jī)制想罕,
效率一般快于for循環(huán)的類(lèi)串行機(jī)制(在for一次循環(huán)中的處理任務(wù)很多時(shí)差距比較大)悠栓。比如這
可以用來(lái)拉取網(wǎng)絡(luò)數(shù)據(jù)后提前算出各個(gè)控件的大小,防止繪制時(shí)計(jì)算按价,提高表單滑動(dòng)流暢性惭适,如
果用for循環(huán),耗時(shí)較多楼镐,并且每個(gè)表單的數(shù)據(jù)沒(méi)有依賴(lài)關(guān)系癞志,所以用dispatch_apply比較好。

**4.死鎖**
- 主線(xiàn)程死鎖示例

  • (void)viewDidLoad{
    [super viewDidLoad];
    NSLog(@"1");
    dispatch_sync(dispatch_get_main_queue(), ^{
    NSLog(@"2");
    });
    NSLog(@"3");
    }
**(1)dispatch_sync**

// 假設(shè)這段代碼執(zhí)行于主隊(duì)列
dispatch_queue_t serialQueue = dispatch_queue_create("serialQueue", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t mainQueue = dispatch_get_main_queue();

// 在主隊(duì)列添加同步任務(wù)
dispatch_sync(mainQueue, ^{
// 任務(wù) ...
});
// 在串行隊(duì)列添加同步任務(wù)
dispatch_sync(serialQueue, ^{
// 任務(wù)
...
dispatch_sync(serialQueue, ^{
// 任務(wù)
...
});
};

**(2)dispatch_apply**

// 因?yàn)閐ispatch_apply會(huì)卡住當(dāng)前線(xiàn)程框产,內(nèi)部的dispatch_apply會(huì)等待外部凄杯,外部的等待
內(nèi)部,所以死鎖秉宿。

dispatch_apply(10, queue, ^(size_t) {
// 任務(wù)
...
dispatch_apply(10, queue, ^(size_t) {
// 任務(wù)
...
});
});


**(3)dispatch_barrier**

dispatch_barrier_sync在串行隊(duì)列和全局并行隊(duì)列里面和dispatch_sync同樣的效果戒突,
所以需考慮同dispatch_sync一樣的死鎖問(wèn)題。

#九描睦、UI相關(guān)
**1.UIView和CALayer是什么區(qū)別和聯(lián)系膊存?**
(1)每個(gè) UIView 內(nèi)部都有一個(gè) CALayer 在背后提供內(nèi)容的繪制和顯示,并且 UIView 的尺寸樣式都由內(nèi)部的 Layer 所提供忱叭。
(2)兩者最明顯的區(qū)別是 View可以接受并處理事件隔崎,而 Layer 不可以,UIView繼承自UIResponder韵丑,可以響應(yīng)用戶(hù)事件爵卒。
(3)UIView主要是對(duì)顯示內(nèi)容的管理,而 CALayer 主要側(cè)重顯示內(nèi)容的繪制撵彻。
(4)在做 iOS 動(dòng)畫(huà)的時(shí)候钓株,修改非 RootLayer的屬性(譬如位置实牡、背景色等)會(huì)默認(rèn)產(chǎn)生隱式動(dòng)畫(huà),而修改UIView則不會(huì)享幽。
**2.如何高性能的給 UIImageView 加個(gè)圓角?**
使用下面的方式會(huì)強(qiáng)制Core Animation提前渲染屏幕的離屏繪制, 而離屏繪制就會(huì)給性能帶來(lái)負(fù)面影響铲掐,會(huì)有卡頓的現(xiàn)象出現(xiàn).

self.view.layer.cornerRadius = 5;
self.view.layer.masksToBounds = YES;

######正確的解決方案:
**(1)使用繪圖技術(shù)**
  • (UIImage *)circleImage{
    // NO代表透明
    UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0);
    // 獲得上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    // 添加一個(gè)圓
    CGRect rect = CGRectMake(0, 0, self.size.width, self.size.height); CGContextAddEllipseInRect(ctx, rect);
    // 裁剪
    CGContextClip(ctx);
    // 將圖片畫(huà)上去
    [self drawInRect:rect];
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    // 關(guān)閉上下文
    UIGraphicsEndImageContext();
    return image;
    }
**(2)使用貝塞爾曲線(xiàn)"切割"個(gè)這個(gè)圖片, 給UIImageView 添加了的圓角,其實(shí)也是通過(guò)繪圖技術(shù)來(lái)實(shí)現(xiàn)的值桩。**

UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake
(0, 0, 100, 100)];
imageView.center = CGPointMake(200, 300);
UIImage *anotherImage = [UIImage imageNamed:@"image"];
UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, NO, 1.0);
[[UIBezierPath bezierPathWithRoundedRect:imageView.bounds cornerRadius:50] addClip];
[anotherImage drawInRect:imageView.bounds];
imageView.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[self.view addSubview:imageView];

**3.如何實(shí)現(xiàn)類(lèi)似QQ的三角形頭像**
(1)Quartz2D

//Quatrz 2D的繪圖功能的三個(gè)核心概念是什么并簡(jiǎn)述其作用
上下文:主要用于描述圖形寫(xiě)入哪里摆霉;
路徑:是在圖層上繪制的內(nèi)容;
狀態(tài):用于保存配置變換的值奔坟、填充和輪廓携栋, alpha 值等。

(2)使用coreGraphics裁剪出一個(gè)三角形
**4.簡(jiǎn)述UITableView的復(fù)用機(jī)制咳秉?**
(1)每次創(chuàng)建cell的時(shí)候通過(guò)dequeueReusableCellWithIdentifier:方法創(chuàng)建cell婉支,它先到緩存池中找指定標(biāo)識(shí)的cell,如果沒(méi)有就直接返回nil;
 (2)如果沒(méi)有找到指定標(biāo)識(shí)的cell澜建,那么會(huì)通過(guò)
initWithStyle:reuseIdentifier:創(chuàng)建一個(gè)cell向挖;
(3)當(dāng)cell離開(kāi)界面就會(huì)被放到緩存池中,以供下次復(fù)用炕舵。
#十何之、開(kāi)源框架(第三方庫(kù))
**1.描述下SDWebImage里面給UIImageView加載圖片的邏輯**

SDWebImage 中為 UIImageView 提供了一個(gè)分類(lèi)UIImageView+WebCache.h, 這個(gè)分類(lèi)
中有一個(gè)最常用的接口sd_setImageWithURL:placeholderImage:,會(huì)在真實(shí)圖片出現(xiàn)前
會(huì)先顯示占位圖片咽筋,當(dāng)真實(shí)圖片被加載出來(lái)后在替換占位圖片.

加載圖片的過(guò)程大致如下:
(1)首先會(huì)在 SDWebImageCache 中尋找圖片是否有對(duì)應(yīng)的緩存, 它會(huì)以u(píng)rl 作為數(shù)據(jù)的索引
先在內(nèi)存中尋找是否有對(duì)應(yīng)的緩存;
(2)如果緩存未找到就會(huì)利用通過(guò)MD5處理過(guò)的key來(lái)繼續(xù)在磁盤(pán)中查詢(xún)對(duì)應(yīng)的數(shù)據(jù), 如果找到了,
就會(huì)把磁盤(pán)中的數(shù)據(jù)加載到內(nèi)存中溶推,并將圖片顯示出來(lái);
(3)如果在內(nèi)存和磁盤(pán)緩存中都沒(méi)有找到,就會(huì)向遠(yuǎn)程服務(wù)器發(fā)送請(qǐng)求奸攻,開(kāi)始下載圖片;
(4)下載后的圖片會(huì)加入緩存中蒜危,并寫(xiě)入磁盤(pán)中;
(5)整個(gè)獲取圖片的過(guò)程都是在子線(xiàn)程中執(zhí)行,獲取到圖片后回到主線(xiàn)程將圖片顯示出來(lái)睹耐。

#十一辐赞、屏幕適配(略)
#十二、TableView滑動(dòng)優(yōu)化
**1.cell復(fù)用
2.如果是cell動(dòng)態(tài)行高硝训,可以計(jì)算高度后緩存占拍。
3.如果不是必要,減少刷新全部cell捎迫,只刷新單行。
4.盡量使用不透明的視圖表牢,cell中盡量少使用動(dòng)畫(huà)窄绒。
5.加載圖片采用異步加載,并且設(shè)置圖片加載的并發(fā)數(shù)崔兴,(滑動(dòng)時(shí)不加載圖片彰导,停止滑動(dòng)時(shí)加載)
6.文字圖片切圓角蛔翅,可以直接使用drawInRect繪制。**
#十三位谋、RunTime(運(yùn)行時(shí))
**1.簡(jiǎn)述Objective-C中調(diào)用方法的過(guò)程(runtime)?**

Objective-C是動(dòng)態(tài)語(yǔ)言山析,每個(gè)方法在運(yùn)行時(shí)會(huì)被動(dòng)態(tài)轉(zhuǎn)為消息發(fā)送,
即:objc_msgSend(receiver, selector)掏父。

過(guò)程如下:

1.objc在向一個(gè)對(duì)象發(fā)送消息時(shí)笋轨,runtime庫(kù)會(huì)根據(jù)對(duì)象的isa指針找到該對(duì)象實(shí)際所屬的類(lèi).
2.然后在該類(lèi)中的方法列表以及其父類(lèi)方法列表中尋找方法運(yùn)行.
3.如果,在最頂層的父類(lèi)(一般也就NSObject)中依然找不到相應(yīng)的方法時(shí)赊淑,轉(zhuǎn)向攔截調(diào)用爵政。
4.如果沒(méi)有寫(xiě)攔截調(diào)用的方法,程序報(bào)錯(cuò)陶缺,拋出異常钾挟。

**2.攔截調(diào)用,三次拯救程序崩潰的機(jī)會(huì)饱岸。**
- Method resolution

1.objc運(yùn)行時(shí)會(huì)調(diào)用+resolveInstanceMethod:或者 +resolveClassMethod:掺出,讓你
有機(jī)會(huì)提供一個(gè)函數(shù)實(shí)現(xiàn)。
2.如果你添加了函數(shù)并返回 YES苫费,那運(yùn)行時(shí)系統(tǒng)就會(huì)重新啟動(dòng)一次消息發(fā)送的過(guò)程
3.如果 resolve 方法返回 NO 汤锨,運(yùn)行時(shí)就會(huì)移到下一步,消息轉(zhuǎn)發(fā)

- Fast forwarding

1.如果目標(biāo)對(duì)象實(shí)現(xiàn)了-forwardingTargetForSelector:黍衙,Runtime 這時(shí)就會(huì)調(diào)用這個(gè)
方法泥畅,給你把這個(gè)消息轉(zhuǎn)發(fā)給其他對(duì)象的機(jī)會(huì)
2.只要這個(gè)方法返回的不是nil和self,整個(gè)消息發(fā)送的過(guò)程就會(huì)被重啟琅翻,當(dāng)然發(fā)送的對(duì)象會(huì)
變成你返回的那個(gè)對(duì)象位仁。
3.否則,就會(huì)繼續(xù)Normal Fowarding方椎。
4.這里叫Fast聂抢,只是為了區(qū)別下一步的轉(zhuǎn)發(fā)機(jī)制。因?yàn)檫@一步不會(huì)創(chuàng)建任何新的對(duì)象棠众,但
Normal forwarding轉(zhuǎn)發(fā)會(huì)創(chuàng)建一個(gè)NSInvocation對(duì)象琳疏,相對(duì)Normal forwarding轉(zhuǎn)
發(fā)更快點(diǎn),所以這里叫Fast forwarding.

- Normal forwarding

1.這一步是Runtime最后一次給你挽救的機(jī)會(huì)闸拿。
2.首先它會(huì)發(fā)送-methodSignatureForSelector:消息獲得函數(shù)的參數(shù)和返回值類(lèi)型空盼。
3.如果-methodSignatureForSelector:返回nil,Runtime則會(huì)發(fā)出
-doesNotRecognizeSelector:消息新荤,程序這時(shí)也就掛掉了揽趾。
4.如果返回了一個(gè)函數(shù)簽名,Runtime就會(huì)創(chuàng)建一個(gè)NSInvocation對(duì)象并發(fā)送
-forwardInvocation:消息給目標(biāo)對(duì)象.


**3.objc中向一個(gè)nil對(duì)象發(fā)送消息將會(huì)發(fā)生什么苛骨?**
(1) 在Objective-C中向nil發(fā)送消息是完全有效的——只是在運(yùn)行時(shí)不會(huì)有任何作用.
(2)如果一個(gè)方法的返回值是一個(gè)對(duì)象/整型變量/結(jié)構(gòu)體/指針類(lèi)型篱瞎,那么發(fā)送給nil的消息返回0(nil).否則苟呐,返回值將是未定義的。
原因如下:

1.objc是動(dòng)態(tài)語(yǔ)言俐筋,每個(gè)方法在運(yùn)行時(shí)會(huì)被動(dòng)態(tài)轉(zhuǎn)為消息發(fā)送牵素,
即:objc_msgSend(receiver, selector).
2.objc在向一個(gè)對(duì)象發(fā)送消息時(shí),runtime庫(kù)會(huì)根據(jù)對(duì)象的isa指針找到該對(duì)象實(shí)際所屬的
類(lèi)澄者,然后在該類(lèi)中的方法列表以及其父類(lèi)方法列表中尋找方法運(yùn)行笆呆,然后再發(fā)送消息的時(shí)候,
objc_msgSend方法不會(huì)返回值闷哆,所謂的返回內(nèi)容都是具體調(diào)用時(shí)執(zhí)行的腰奋。
3.如果向一個(gè)nil對(duì)象發(fā)送消息,首先在尋找對(duì)象的isa指針時(shí)就是0地址返回了抱怔,所以不會(huì)出
現(xiàn)任何錯(cuò)誤.

**4.runtime如何實(shí)現(xiàn)weak變量的自動(dòng)置nil劣坊?**

//weak的特點(diǎn)
weak策略表明該屬性定義了一種“非擁有關(guān)系” (nonowning relationship)。為這種屬性
設(shè)置新值時(shí)屈留,設(shè)置方法既不保留新值局冰,也不釋放舊值。此特質(zhì)同assign類(lèi)似;然而在屬性所指
的對(duì)象遭到摧毀時(shí)灌危,屬性值也會(huì)清空(nil out)康二。

runtime對(duì)注冊(cè)的類(lèi),會(huì)進(jìn)行布局勇蝙,會(huì)將 weak 對(duì)象放入一個(gè) hash 表中沫勿。用 weak 指向
的對(duì)象內(nèi)存地址作為 key,當(dāng)此對(duì)象的引用計(jì)數(shù)為0的時(shí)候會(huì)調(diào)用對(duì)象的 dealloc 方法味混,假
設(shè) weak 指向的對(duì)象內(nèi)存地址是a产雹,那么就會(huì)以a為key,在這個(gè) weak hash表中搜索翁锡,找到
所有以a為key的 weak 對(duì)象蔓挖,從而設(shè)置為 nil。

**5.一個(gè)Objective-C對(duì)象如何進(jìn)行內(nèi)存布局馆衔?(考慮有父類(lèi)的情況)**

1.所有父類(lèi)的成員變量和自己的成員變量都會(huì)存放在該對(duì)象所對(duì)應(yīng)的存儲(chǔ)空間中
2.父類(lèi)的方法和自己的方法都會(huì)緩存在類(lèi)對(duì)象的方法緩存中瘟判,類(lèi)方法是緩存在元類(lèi)對(duì)象中.
3.每一個(gè)對(duì)象內(nèi)部都有一個(gè)isa指針,指向他的類(lèi)對(duì)象,類(lèi)對(duì)象中存放著本對(duì)象的如下信息:
對(duì)象方法列表
成員變量的列表
屬性列表
4.類(lèi)對(duì)象中也有一個(gè)isa指針指向它的元類(lèi)(meta class),即類(lèi)對(duì)象是元類(lèi)的實(shí)例角溃。元類(lèi)內(nèi)
部存放的是類(lèi)方法列表拷获,根元類(lèi)的isa指針指向自己,superclass指針指向NSObject類(lèi).
5.根類(lèi)對(duì)象就是NSObject减细,它的super class指針指向nil.

#十四匆瓜、RunLoop
[深入理解RunLoop(運(yùn)行循環(huán))](http://www.reibang.com/p/1b091c97c0af)
#十五、app打包上架和SVN/Git協(xié)作開(kāi)發(fā)(代碼沖突)
(1)一種版本控制工具。
(2)優(yōu)點(diǎn):集中管理陕壹,保證安全;缺點(diǎn):需要網(wǎng)絡(luò)支持树埠,容易沖突糠馆。
(3)避免沖突:下載--更新--提交--避免不通人修改同一處代碼。
#十六怎憋、即時(shí)通訊
1.[iOS之環(huán)信即時(shí)通訊實(shí)現(xiàn)步驟](http://www.reibang.com/p/85d3dc78be0d)
2.[iOS開(kāi)發(fā)融云即時(shí)通訊集成詳細(xì)步驟](http://www.reibang.com/p/713dbbaef2f8)
3.[阿里百川SDK集成詳細(xì)步驟](http://www.reibang.com/p/7a877fed766b)
#十七又碌、推送通知
(1)APP客戶(hù)端申請(qǐng)推送服務(wù),同時(shí)設(shè)備向蘋(píng)果APNS服務(wù)器發(fā)送請(qǐng)求绊袋。
(2)APNS服務(wù)器接受請(qǐng)求毕匀,返回deviceToken給你設(shè)備上的程序。
(3)客戶(hù)端將deviceToken發(fā)送給極光后臺(tái)癌别,后臺(tái)接受儲(chǔ)存皂岔,同時(shí)向APNS服務(wù)器發(fā)送通知信息
(4)APNS服務(wù)器將消息發(fā)送給deviceToken對(duì)應(yīng)的設(shè)備的應(yīng)用程序。
#十八展姐、支付
商戶(hù)簽約 ( 商戶(hù)ID和賬號(hào)ID )--下載公私鑰(加密簽名用)--支付寶SDK--生成訂單--調(diào)用支付寶客戶(hù)端--支付寶客戶(hù)端和內(nèi)部服務(wù)器--支付完畢躁垛,返回結(jié)果給客戶(hù)端和服務(wù)器
#十九、JS和OC相互調(diào)用
- [JS和OC的交互(基于UIWebView)](http://www.reibang.com/p/c3baa6ea60b8)
- [js oc相互調(diào)用的三種方法](http://www.reibang.com/p/dbddfc0eaa26)
- [IOS中 使用JavaScriptCore 實(shí)現(xiàn)OC與JS的交互](http://www.reibang.com/p/cdaf9bc3d65d)
- [UIWebView與JS簡(jiǎn)單交互(刪除標(biāo)簽和獲取某個(gè)標(biāo)簽的內(nèi)容)](http://www.reibang.com/p/e584eaccb3a6)

#二十圾笨、核心動(dòng)畫(huà)教馆。
**1.如何使用核心動(dòng)畫(huà)?**
  (1)創(chuàng)建
  (2)設(shè)置相關(guān)屬性
  (3)添加到CALayer上擂达,會(huì)自動(dòng)執(zhí)行動(dòng)畫(huà)
#二十一土铺、圖文混排
- [iOS圖文混排](http://www.reibang.com/p/a8c98e684918)
- [TextKit 探究](http://www.reibang.com/p/3f445d7f44d6)
- [NSAttributedString(圖文混排)](http://www.reibang.com/p/6ec86db11bc1)

#二十二、自定義控件
**你是怎么封裝一個(gè)view的?**
可以通過(guò)純代碼或者xib的方式來(lái)封裝子控件,建立一個(gè)跟view相關(guān)的模型板鬓,然后將模型數(shù)據(jù)傳給view悲敷,通過(guò)模型上的數(shù)據(jù)給view的子控件賦值.

// 純代碼初始化控件時(shí)一定會(huì)走這個(gè)方法

  • (instancetype)initWithFrame:(CGRect)frame
    {
    if(self = [super initWithFrame:frame])
    {
    [self setup];
    }
    return self;
    }
    // 通過(guò)xib初始化控件時(shí)一定會(huì)走這個(gè)方法
  • (id)initWithCoder:(NSCoder *)aDecoder
    {
    if(self = [super initWithCoder:aDecoder])
    {
    [self setup];
    }
    return self;
    }
  • (void)setup
    {
    // 初始化代碼
    }
#二十三、內(nèi)存泄漏穗熬,代碼調(diào)試
**1.代碼調(diào)試**
log--控制臺(tái)po--全局?jǐn)帱c(diǎn)--條件斷點(diǎn)--開(kāi)啟僵尸對(duì)象--分析層級(jí)結(jié)構(gòu)
**開(kāi)啟僵尸對(duì)象:首先打開(kāi)“Edit Scheme”镀迂,然后選擇Diagnostics選項(xiàng)卡,勾選Enable NSZombie Objects選項(xiàng)唤蔗。**
#二十四探遵、MVC和MVVM
[iOS MVVM與MVC](http://www.reibang.com/p/9a99a93201e3)
#二十五、響應(yīng)鏈和生命周期妓柜。
**1.響應(yīng)鏈**

響應(yīng)者鏈通常是由視圖(UIView)構(gòu)成的箱季,一個(gè)視圖的下一個(gè)響應(yīng)者是它的視圖控制器
(如果有的話(huà)),然后再傳遞給它的父視圖視圖控制器(如果有的話(huà))的下一個(gè)響應(yīng)者為其
管理的視圖的父視圖棍掐。在視圖層次結(jié)構(gòu)的最頂級(jí)視圖藏雏,如果也不能處理收到的事件或者
消息,就會(huì)把事件傳遞給UIWindow對(duì)象進(jìn)行處理如果window對(duì)象也不處理作煌,則將事件
或消息傳遞給UIApplication對(duì)象掘殴,如果UIApplication也不處理則丟棄赚瘦。
補(bǔ)充:如何判斷上一個(gè)響應(yīng)者?
如果當(dāng)前這個(gè)view是控制器的view,那么控制器就是上一個(gè)響應(yīng)者
如果當(dāng)前這個(gè)view不是控制器的view奏寨,那么父控件就是上一個(gè)響應(yīng)者

**2.觸摸事件的傳遞**

觸摸事件的傳遞是從父控件傳遞到子控件
如果父控件不能接收觸摸事件起意,那么子控件就不可能接收到觸摸事件
不能接受觸摸事件的四種情況
不接收用戶(hù)交互,即:userInteractionEnabled = NO
隱藏病瞳,即:hidden = YES
透明揽咕,即:alpha <= 0.01
未啟用,即:enabled = NO
提示:UIImageView的userInteractionEnabled默認(rèn)就是NO套菜,因此UIImageView以及它的
子控件默認(rèn)是不能接收觸摸事件的

如何找到最合適處理事件的控件:
首先亲善,判斷自己能否接收觸摸事件
可以通過(guò)重寫(xiě)hitTest:withEvent:方法驗(yàn)證
其次,判斷觸摸點(diǎn)是否在自己身上
對(duì)應(yīng)方法pointInside:withEvent:
從后往前(先遍歷最后添加的子控件)遍歷子控件逗柴,重復(fù)前面的兩個(gè)步驟
如果沒(méi)有符合條件的子控件蛹头,那么就自己處理

**3.事件分發(fā)**

iOS系統(tǒng)檢測(cè)到手指觸摸(Touch)操作時(shí)會(huì)將其打包成一個(gè)UIEvent對(duì)象,并放入當(dāng)前活動(dòng)
Application的事件隊(duì)列嚎于,單例的UIApplication會(huì)從事件隊(duì)列中取出觸摸事件并傳遞給
單例的UIWindow來(lái)處理掘而,UIWindow對(duì)象首先會(huì)使用hitTest:withEvent:方法尋找此次
Touch操作初始點(diǎn)所在的視圖(View),即需要將觸摸事件傳遞給其處理的視圖于购,這個(gè)過(guò)程稱(chēng)
之為hit-test view袍睡。

**4.生命周期**

// 自定義控制器view,這個(gè)方法只有實(shí)現(xiàn)了才會(huì)執(zhí)行

  • (void)loadView
    {
    self.view = [[UIView alloc] init];
    self.view.backgroundColor = [UIColor orangeColor];
    }
    // view是懶加載肋僧,只要view加載完畢就調(diào)用這個(gè)方法
  • (void)viewDidLoad
    {
    [super viewDidLoad];
    NSLog(@"%s",func);
    }
    // view即將顯示
  • (void)viewWillAppear:(BOOL)animated
    {
    [super viewWillAppear:animated];
    NSLog(@"%s",func);
    }
    // view即將開(kāi)始布局子控件
  • (void)viewWillLayoutSubviews
    {
    [super viewWillLayoutSubviews];
    NSLog(@"%s",func);
    }
    // view已經(jīng)完成子控件的布局
  • (void)viewDidLayoutSubviews
    {
    [super viewDidLayoutSubviews];
    NSLog(@"%s",func);
    }
    // view已經(jīng)出現(xiàn)
  • (void)viewDidAppear:(BOOL)animated
    {
    [super viewDidAppear:animated];
    NSLog(@"%s",func);
    }
    // view即將消失
  • (void)viewWillDisappear:(BOOL)animated
    {
    [super viewWillDisappear:animated];
    NSLog(@"%s",func);
    }
    // view已經(jīng)消失
  • (void)viewDidDisappear:(BOOL)animated
    {
    [super viewDidDisappear:animated];
    NSLog(@"%s",func);
    }
    // 收到內(nèi)存警告
  • (void)didReceiveMemoryWarning
    {
    [super didReceiveMemoryWarning];
    NSLog(@"%s",func);
    }
    // 方法已過(guò)期斑胜,即將銷(xiāo)毀view
  • (void)viewWillUnload
    {
    }
    // 方法已過(guò)期,已經(jīng)銷(xiāo)毀view
  • (void)viewDidUnload
    {
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末嫌吠,一起剝皮案震驚了整個(gè)濱河市止潘,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌辫诅,老刑警劉巖凭戴,帶你破解...
    沈念sama閱讀 221,695評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異炕矮,居然都是意外死亡么夫,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)肤视,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)档痪,“玉大人,你說(shuō)我怎么就攤上這事邢滑「” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,130評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)乐纸。 經(jīng)常有香客問(wèn)我衬廷,道長(zhǎng),這世上最難降的妖魔是什么汽绢? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,648評(píng)論 1 297
  • 正文 為了忘掉前任泵督,我火速辦了婚禮,結(jié)果婚禮上庶喜,老公的妹妹穿的比我還像新娘。我一直安慰自己救鲤,他們只是感情好久窟,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,655評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著本缠,像睡著了一般斥扛。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上丹锹,一...
    開(kāi)封第一講書(shū)人閱讀 52,268評(píng)論 1 309
  • 那天稀颁,我揣著相機(jī)與錄音,去河邊找鬼楣黍。 笑死匾灶,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的租漂。 我是一名探鬼主播阶女,決...
    沈念sama閱讀 40,835評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼哩治!你這毒婦竟也來(lái)了秃踩?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,740評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤业筏,失蹤者是張志新(化名)和其女友劉穎憔杨,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體蒜胖,經(jīng)...
    沈念sama閱讀 46,286評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡消别,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,375評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了翠勉。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片妖啥。...
    茶點(diǎn)故事閱讀 40,505評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖对碌,靈堂內(nèi)的尸體忽然破棺而出荆虱,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布怀读,位于F島的核電站诉位,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏菜枷。R本人自食惡果不足惜苍糠,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,873評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望啤誊。 院中可真熱鬧岳瞭,春花似錦、人聲如沸蚊锹。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,357評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)牡昆。三九已至姚炕,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間丢烘,已是汗流浹背柱宦。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,466評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留播瞳,地道東北人掸刊。 一個(gè)月前我還...
    沈念sama閱讀 48,921評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像赢乓,于是被迫代替她去往敵國(guó)和親痒给。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,515評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • iOS面試小貼士 ———————————————回答好下面的足夠了------------------------...
    不言不愛(ài)閱讀 1,990評(píng)論 0 7
  • 多線(xiàn)程骏全、特別是NSOperation 和 GCD 的內(nèi)部原理苍柏。運(yùn)行時(shí)機(jī)制的原理和運(yùn)用場(chǎng)景。SDWebImage的原...
    LZM輪回閱讀 2,009評(píng)論 0 12
  • 史上最全的iOS面試題及答案 iOS面試小貼士———————————————回答好下面的足夠了----------...
    Style_偉閱讀 2,359評(píng)論 0 35
  • OC的理解與特性 OC作為一門(mén)面向?qū)ο蟮恼Z(yǔ)言姜贡,自然具有面向?qū)ο蟮恼Z(yǔ)言特性:封裝试吁、繼承、多態(tài)楼咳。它既具有靜態(tài)語(yǔ)言的特性...
    克魯?shù)吕?/span>閱讀 450評(píng)論 0 0
  • OC的理解與特性O(shè)C作為一門(mén)面向?qū)ο蟮恼Z(yǔ)言熄捍,自然具有面向?qū)ο蟮恼Z(yǔ)言特性:封裝、繼承母怜、多態(tài)余耽。它既具有靜態(tài)語(yǔ)言的特性(...
    LIANMING_LI閱讀 516評(píng)論 0 0