iOS常見問題總結(jié)

1.是否可以把比較耗時的操作放在NSNotificationCenter中處理怔檩?為什么?應(yīng)該如何處理丽旅?

參考鏈接: http://www.imlifengfeng.com/blog/?p=620

2.CAAnimation是什么忱屑?寫一下它的層次結(jié)構(gòu)(主要寫下其各個子類)

參考鏈接: http://www.imlifengfeng.com/blog/?p=548

3.Cocoa的Foundation對象與Core Foundation對象通過什么關(guān)鍵字進(jìn)行轉(zhuǎn)換篮昧?這些關(guān)鍵字有什么區(qū)別?

參考鏈接: https://blog.csdn.net/yiyaaixuexi/article/details/8553659

4.利用NSOperation與NSOperationQueue處理多線程時午磁,有3個NSOperation分別為A尝抖、B、C,要求A迅皇、B執(zhí)行完之后才執(zhí)行C,如何做昧辽?
    // 1.創(chuàng)建隊列
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    // 2.創(chuàng)建操作
    NSBlockOperation *operationA = [NSBlockOperation   blockOperationWithBlock:^{
        for (int i = 0; i < 2; i++) {
            [NSThread sleepForTimeInterval:2]; // 模擬耗時操作
            NSLog(@"A---%@", [NSThread currentThread]); // 打印當(dāng)前線程
        }
    }];
    NSBlockOperation *operationB = [NSBlockOperation blockOperationWithBlock:^{
        for (int i = 0; i < 2; i++) {
            [NSThread sleepForTimeInterval:2]; // 模擬耗時操作
            NSLog(@"B---%@", [NSThread currentThread]); // 打印當(dāng)前線程
        }
    }];
    NSBlockOperation *operationC = [NSBlockOperation blockOperationWithBlock:^{
        for (int i = 0; i < 2; i++) {
            [NSThread sleepForTimeInterval:2]; // 模擬耗時操作
            NSLog(@"C---%@", [NSThread currentThread]); // 打印當(dāng)前線程
        }
    }];
    //添加依賴
    [operationC addDependency:operationA];
    [operationC addDependency:operationB];
   
    [queue addOperation:operationA];
    [queue addOperation:operationB];
    [queue addOperation:operationC];
5. KVO是什么?內(nèi)部是如何實現(xiàn)的登颓?

參考鏈接: http://www.reibang.com/p/e59bb8f59302

6.什么是中間人攻擊搅荞?如何避免?

參考鏈接: http://jashoka.com/2018/03/15/iOS-https防止中間人攻擊/

iOS實現(xiàn)代碼

// 單向認(rèn)證只需這段代碼就行
....
shareManager = [AFHTTPSessionManager manager];
shareManager.securityPolicy = [self customSecurityPolicy];
.....
+ (AFSecurityPolicy*)customSecurityPolicy
{
    // /先導(dǎo)入證書
    NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"server" ofType:@"cer"];//證書的路徑
    NSData *certData = [NSData dataWithContentsOfFile:cerPath];

    // AFSSLPinningModeCertificate 使用證書驗證模式
    AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];

    // allowInvalidCertificates 是否允許無效證書(也就是自建的證書)框咙,默認(rèn)為NO
    // 如果是需要驗證自建證書咕痛,需要設(shè)置為YES
    securityPolicy.allowInvalidCertificates = YES;

    //validatesDomainName 是否需要驗證域名,默認(rèn)為YES喇嘱;
    //假如證書的域名與你請求的域名不一致茉贡,需把該項設(shè)置為NO;如設(shè)成NO的話者铜,即服務(wù)器使用其他可信任機(jī)構(gòu)頒發(fā)的證書腔丧,也可以建立連接,這個非常危險作烟,建議打開愉粤。
    //置為NO,主要用于這種情況:客戶端請求的是子域名俗壹,而證書上的是另外一個域名科汗。因為SSL證書上的域名是獨立的藻烤,假如證書上注冊的域名是www.google.com绷雏,那么mail.google.com是無法驗證通過的头滔;當(dāng)然,有錢可以注冊通配符的域名*.google.com涎显,但這個還是比較貴的坤检。
   //如置為NO,建議自己添加對應(yīng)域名的校驗邏輯期吓。
    securityPolicy.validatesDomainName = NO;

    securityPolicy.pinnedCertificates = @[certData];

    return securityPolicy;
}
// 雙向認(rèn)證需添加這些代碼
[shareManager setSessionDidReceiveAuthenticationChallengeBlock:^NSURLSessionAuthChallengeDisposition(NSURLSession *session, NSURLAuthenticationChallenge *challenge, NSURLCredential *__autoreleasing *_credential) {
    NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
    __autoreleasing NSURLCredential *credential = nil;
    if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
        if ([shareManager.securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) {
            credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
            if(credential) {
                disposition =NSURLSessionAuthChallengeUseCredential;
            } else {
                disposition =NSURLSessionAuthChallengePerformDefaultHandling;
            }
        } else {
            disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge;
        }
    } else {
        SecIdentityRef identity = NULL;
        SecTrustRef trust = NULL;
        NSString *p12 = [[NSBundle mainBundle] pathForResource:@"client"ofType:@"p12"];
        NSFileManager *fileManager =[NSFileManager defaultManager];
        
        if(![fileManager fileExistsAtPath:p12])
        {
            NSLog(@"client.p12:not exist");
        }
        else
        {
            NSData *PKCS12Data = [NSData dataWithContentsOfFile:p12];
            
            if ([[self class] extractIdentity:&identity andTrust:&trust fromPKCS12Data:PKCS12Data])
            {
                SecCertificateRef certificate = NULL;
                SecIdentityCopyCertificate(identity, &certificate);
                const void*certs[] = {certificate};
                CFArrayRef certArray =CFArrayCreate(kCFAllocatorDefault, certs,1,NULL);
                credential =[NSURLCredential credentialWithIdentity:identity certificates:(__bridge  NSArray*)certArray persistence:NSURLCredentialPersistencePermanent];
                disposition =NSURLSessionAuthChallengeUseCredential;
            }
        }
    }
    *_credential = credential;
    return disposition;
}]

+ (BOOL)extractIdentity:(SecIdentityRef*)outIdentity andTrust:(SecTrustRef *)outTrust fromPKCS12Data:(NSData *)inPKCS12Data {
    OSStatus securityError = errSecSuccess;
    //client certificate password
    NSDictionary*optionsDictionary = [NSDictionary dictionaryWithObject:@"your p12 file pwd"
                                                                 forKey:(__bridge id)kSecImportExportPassphrase];
    
    CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
    securityError = SecPKCS12Import((__bridge CFDataRef)inPKCS12Data,(__bridge CFDictionaryRef)optionsDictionary,&items);
    
    if(securityError == 0) {
        CFDictionaryRef myIdentityAndTrust =CFArrayGetValueAtIndex(items,0);
        const void*tempIdentity =NULL;
        tempIdentity= CFDictionaryGetValue (myIdentityAndTrust,kSecImportItemIdentity);
        *outIdentity = (SecIdentityRef)tempIdentity;
        const void*tempTrust =NULL;
        tempTrust = CFDictionaryGetValue(myIdentityAndTrust,kSecImportItemTrust);
        *outTrust = (SecTrustRef)tempTrust;
    } else {
        NSLog(@"Failedwith error code %d",(int)securityError);
        return NO;
    }
    return YES;
}
7. 反射是什么早歇?可以舉出幾個應(yīng)用場景么?

參考鏈接1: https://cdn2.jianshu.io/p/4fde3afcaf1a
參考鏈接2: http://www.reibang.com/p/5bbde2480680

8. __weak修飾符與__unsafe_unretained修飾符有相同點是什么讨勤?有什么區(qū)別呢箭跳?

__weak__unsafe_unretained都不會對對象產(chǎn)生強(qiáng)引用, 區(qū)別是__weak修飾的指針一旦它指向的對象被銷毀了,__weak修飾的指針會被置為nil潭千,比較安全谱姓,_unsafe_unretained修飾的指針指向的對象被銷毀后,__unsafe_unretained修飾的指針仍然指向原對象的內(nèi)存空間刨晴,會產(chǎn)生野指針錯誤屉来。

9. __weak修飾的指針指向的對象會被自動置為nil,其實現(xiàn)原理是什么狈癞?

當(dāng)對象被廢棄之后茄靠,對象會調(diào)用dealloc方法,在delloc內(nèi)部實現(xiàn)中蝶桶,通過當(dāng)前對象慨绳,經(jīng)過哈希算法,在SideTables當(dāng)中真竖,找到它所屬的SideTable,然后根據(jù)當(dāng)前對象指針儡蔓,訪問SideTable中的弱引用表,去查找它所對用的弱引用表疼邀,然后遍歷弱引用表中的所有弱引用指針喂江,把弱引用指針置為nil。

10. release實現(xiàn)原理是怎樣的旁振?

通過當(dāng)前對象获询,經(jīng)過哈希算法,在SideTables當(dāng)中拐袜,找到它所屬的SideTable吉嚣,然后再根據(jù)當(dāng)前對象指針訪問SideTable中的引用計數(shù)表,去查找它對應(yīng)的引用計數(shù)表蹬铺,查找到之后把對應(yīng)的值進(jìn)行減1操作尝哆。

11. retain實現(xiàn)原理是怎樣的?

通過當(dāng)前對象甜攀,經(jīng)過哈希算法秋泄,在SideTables當(dāng)中琐馆,找到它所屬的SideTable,然后再根據(jù)當(dāng)前對象指針訪問SideTable中的引用計數(shù)表恒序,去查找它所對應(yīng)的引用計數(shù)表瘦麸,查找到之后把對應(yīng)的值進(jìn)行加1操作。

12. Autoreleasepool的實現(xiàn)原理是怎樣的歧胁?

Autoreleasepool它的實現(xiàn)是以棧為節(jié)點滋饲,以雙向鏈表的形式,組合而成的數(shù)據(jù)結(jié)構(gòu)喊巍。

13. Autoreleasepool為何可以嵌套使用屠缭?

多層嵌套就是多次插入哨兵對象。

14. 在非ARC中崭参,可以對哪些對象加上autorelease關(guān)鍵字勿她?它的作用是什么?被autorelease修飾的對象什么時候釋放阵翎?

NSArray逢并、NSDictionary、NSString等對象在初始化init郭卫、retain砍聊、copy等時可以autorelease。對象執(zhí)行autorelease方法會將對象添加到自動釋放池中贰军,當(dāng)自動釋放池銷毀時玻蝌,自動釋放池中所有對象進(jìn)行release操作,對象執(zhí)行autorelease方法自身引用計數(shù)不會改變词疼,而且返回對象本身俯树。autorelease的作用,只是把release調(diào)用延遲了,每次的autorelease把對象放入autoreleasepool中贰盗,當(dāng)pool釋放時许饿,該pool所有對象都會進(jìn)行release操作。

15.一個NSObject對象占用多少內(nèi)存舵盈?

系統(tǒng)分配16個字節(jié)給NSObject對象陋率,但NSObject對象內(nèi)部只使用了8個字節(jié)的空間(64bit環(huán)境下,可以通過class_getInstanceSize函數(shù)獲得)

16.說說深拷貝與淺拷貝

淺拷貝:淺拷貝之后原指針和拷貝后的指針是指向同一個對象,不會產(chǎn)生新的對象秽晚。
深拷貝:深拷貝之后原指針和拷貝后的指針指向不同的對象瓦糟,會產(chǎn)生新的對象。
copy: 對不可變對象為淺拷貝赴蝇,對可變對象為深拷貝菩浙。
mutableCopy: 不管是可變對象還是不可變對象都為深拷貝。

17.如何實現(xiàn)對NSArray或者NSMutableArray中的對象實現(xiàn)深拷貝?

使用歸檔解檔即可劲蜻。

    NSMutableString *str1 = [NSMutableString stringWithFormat:@"非容器可變對象"];
    NSArray *array = [NSArray arrayWithObjects:str1, @"非容器不可變對象", nil];
    
    NSMutableArray *mutableArray = [array mutableCopy];
    
    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:mutableArray];
    NSMutableArray *newMutableArray = [NSKeyedUnarchiver unarchiveObjectWithData:data];
    
    NSLog(@"===原對象===");
    NSLog(@"array[0] : %p, array[1] : %p", array[0], array[1]);
    
    NSLog(@"===新對象===");
    NSLog(@"mutableArray[0] : %p, mutableArray[1] : %p", mutableArray[0], mutableArray[1]);
    
    NSLog(@"===完全拷貝對象===");
    NSLog(@"newMutableArray[0] : %p, newMutableArray[1] : %p", newMutableArray[0], newMutableArray[1]);

打印結(jié)果


1.png
18.自定義對象的深拷貝
#import <Foundation/Foundation.h>

@interface MJDog : NSObject

@property (nonatomic,copy)NSString *name;

@end
#import "MJDog.h"

@implementation MJDog

- (id)copyWithZone:(NSZone *)zone{
    MJDog *dog = [MJDog allocWithZone:zone];
    dog.name = [self.name mutableCopy];
    return dog;
}

- (id)mutableCopyWithZone:(NSZone *)zone{
    MJDog *dog = [MJDog allocWithZone:zone];
    dog.name = [self.name mutableCopy];
    return dog;
}
@end

#import <Foundation/Foundation.h>
#import "MJDog.h"
@interface MJPerson : NSObject<NSCopying,NSMutableCopying>
@property(nonatomic,copy)NSString *name;
@property (nonatomic,copy)MJDog *dog;
@end
#import "MJPerson.h"
@implementation MJPerson
- (id)copyWithZone:(NSZone *)zone{
    MJPerson *person = [MJPerson allocWithZone:zone];
    person.name = [self.name mutableCopy];
    person.dog = self.dog;
    return person;
}
- (id)mutableCopyWithZone:(NSZone *)zone{
    MJPerson *person = [MJPerson allocWithZone:zone];
    person.name = self.name;
    person.dog = self.dog;
    return person;
}
@end

#import "ViewController.h"
#import "MJPerson.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    MJPerson *person = [[MJPerson alloc] init];
    person.name = @"日天";
    MJDog *dog = [[MJDog alloc] init];
    person.dog = dog;
    MJPerson *person1 = [person copy];
    NSLog(@"person.name = %p,person1.name=%p",person.name,person1.name);
}
19.使用NSTimer應(yīng)該注意哪些問題陆淀?
  1. 子線程啟動定時器問題
    NSTimer是依賴runloop的,在主線程中因為默認(rèn)啟動了runloop斋竞,可是子線程沒有默認(rèn)的runloop,因此在子線程啟動定時器是不生效的秃殉。
    解決防方案坝初,在子線程啟動runloop
  dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self s    elector:@selector(timered:) userInfo:nil repeats:YES];
        [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
        [[NSRunLoop currentRunLoop] run];
    });
  1. UIScrollView滑動過程中定時器失效
    解決方案就是把timer添加到runloop的NSRunLoopCommonModes。UITrackingRunLoopMode和kCFRunLoopDefaultMode都被標(biāo)記為common模式钾军,所以只需要將timer的模式設(shè)置為NSRunLoopCommonModes鳄袍,就可以在默認(rèn)模式和追蹤模式都能運(yùn)行。
  2. 循環(huán)引用問題
    NSTimer會對target產(chǎn)生強(qiáng)引用吏恭,如果target又對timer產(chǎn)生強(qiáng)引用拗小,這樣就會引發(fā)循環(huán)引用。
    解決方案一:
#import <Foundation/Foundation.h>
@interface NSTimer (BlockTimer)
+ (NSTimer*)scheduledTimerWithTimerInterval:(NSTimeInterval)interval repeats:(BOOL)repeats blockTimer:(void (^)(NSTimer *))block;
@end


#import "NSTimer+BlockTimer.h"
@implementation NSTimer (BlockTimer)
+ (NSTimer*)scheduledTimerWithTimerInterval:(NSTimeInterval)interval
                                    repeats:(BOOL)repeats
                                 blockTimer:(void (^)(NSTimer *))block{
    NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:interval target:self selector:@selector(timered:) userInfo:[block copy] repeats:repeats];
    return timer;
}

+ (void)timered:(NSTimer *)timer{
    void (^block)(NSTimer *timer) = timer.userInfo;
    block(timer);
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末樱哼,一起剝皮案震驚了整個濱河市哀九,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌搅幅,老刑警劉巖阅束,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異茄唐,居然都是意外死亡息裸,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進(jìn)店門沪编,熙熙樓的掌柜王于貴愁眉苦臉地迎上來呼盆,“玉大人,你說我怎么就攤上這事蚁廓》闷裕” “怎么了?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵相嵌,是天一觀的道長挽荠。 經(jīng)常有香客問我,道長平绩,這世上最難降的妖魔是什么圈匆? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮捏雌,結(jié)果婚禮上跃赚,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好纬傲,可當(dāng)我...
    茶點故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布满败。 她就那樣靜靜地躺著,像睡著了一般叹括。 火紅的嫁衣襯著肌膚如雪算墨。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天汁雷,我揣著相機(jī)與錄音净嘀,去河邊找鬼。 笑死侠讯,一個胖子當(dāng)著我的面吹牛挖藏,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播厢漩,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼膜眠,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了溜嗜?” 一聲冷哼從身側(cè)響起宵膨,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎炸宵,沒想到半個月后柄驻,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡焙压,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年鸿脓,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片涯曲。...
    茶點故事閱讀 38,064評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡野哭,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出幻件,到底是詐尸還是另有隱情拨黔,我是刑警寧澤,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布绰沥,位于F島的核電站篱蝇,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏徽曲。R本人自食惡果不足惜零截,卻給世界環(huán)境...
    茶點故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望秃臣。 院中可真熱鬧涧衙,春花似錦哪工、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至撤嫩,卻和暖如春偎捎,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背序攘。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工茴她, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人两踏。 一個月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓败京,卻偏偏與公主長得像兜喻,于是被迫代替她去往敵國和親梦染。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,802評論 2 345

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