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é)果
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)該注意哪些問題陆淀?
- 子線程啟動定時器問題
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];
});
- UIScrollView滑動過程中定時器失效
解決方案就是把timer添加到runloop的NSRunLoopCommonModes。UITrackingRunLoopMode和kCFRunLoopDefaultMode都被標(biāo)記為common模式钾军,所以只需要將timer的模式設(shè)置為NSRunLoopCommonModes鳄袍,就可以在默認(rèn)模式和追蹤模式都能運(yùn)行。 - 循環(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);
}