題目來源自這里,筆者對知識類問題和經(jīng)驗類問題做了解答,答案有遺漏的地方希望大家能補充,這是你能用到的面試題(一)
Push Notification 是如何工作的垦梆?
- 推送通知分為兩種,一個是本地推送,一個是遠程推送
- 本地推送:不需要聯(lián)網(wǎng)也可以推送,是開發(fā)人員在APP內設定特定的時間來提醒用戶干什么
- 遠程推送:需要聯(lián)網(wǎng),用戶的設備會于蘋果APNS服務器形成一個長連接,用戶設備會發(fā)送uuid和Bundle idenidentifier給蘋果服務器,蘋果服務器會加密生成一個deviceToken給用戶設備,然后設備會將deviceToken發(fā)送給APP的服務器,服務器會將deviceToken存進他們的數(shù)據(jù)庫,這時候如果有人發(fā)送消息給我,服務器端就會去查詢我的deviceToken,然后將deviceToken和要發(fā)送的信息發(fā)送給蘋果服務器,蘋果服務器通過deviceToken找到我的設備并將消息推送到我的設備上,這里還有個情況是如果APP在線,那么APP服務器會于APP產(chǎn)生一個長連接,這時候APPF服務器會直接通過deviceToken將消息推送到設備上
什么是 Runloop?
是一個與線程相關的機制,可以理解為一個循環(huán),在這個循環(huán)里面等待事件然后處理事件.而這個循環(huán)是基于線程的,在Cocoa中每個線程都有它的runroop,通過他這樣的機制,線程可以在沒有事件要處理的時候休息,有事件運行,減輕CPU壓力,這題可以衍生出為什么在滑動時會導致定時器失敗,在下面有解答
Toll-Free Bridging 是什么八秃?什么情況下會使用?
Toll-Free Bridging用于在Foundation對象與Core Foundation對象之間交換數(shù)據(jù),俗稱橋接
- 在ARC環(huán)境下,Foundation對象轉成 Core Foundation對象
- 使用
__bridge
橋接以后ARC會自動2個對象 - 使用
__bridge_retained
橋接需要手動釋放Core Foundation對象
- 使用
- 在ARC環(huán)境下, Core Foundation對象轉成 Foundation對象
- 使用
__bridge
橋接,如果Core Foundation對象被釋放,Foundation對象也同時不能使用了,需要手動管理Core Foundation對象 - 使用
__bridge_transfer
橋接,系統(tǒng)會自動管理2個對象
- 使用
當系統(tǒng)出現(xiàn)內存警告時會發(fā)生什么据途?
- 會將不在當前窗口上的view暫時移除
- 如果放任內存警告,最終會導致軟件強制被系統(tǒng)關閉
什么是 Protocol澄峰,Delegate 一般是怎么用的?
- 協(xié)議是一個方法簽名的列表呀潭,在其中可以定義若干個方法,遵守該協(xié)議的類可以實現(xiàn)協(xié)議里的方法,在協(xié)議中使用
@property
只會生成setter和getter方法的聲明 - delegate用法:成為一個類的代理,可以去實現(xiàn)協(xié)議里的方法
autorelease 對象在什么情況下會被釋放?
- 分兩種情況:手動干預釋放和系統(tǒng)自動釋放
- 手動干預釋放就是指定autoreleasepool,當前作用域大括號結束就立即釋放
- 系統(tǒng)自動去釋放:不手動指定autoreleasepool,Autorelease對象會在當前的 runloop 迭代結束時釋放
- kCFRunLoopEntry(1):第一次進入會自動創(chuàng)建一個autorelease
- kCFRunLoopBeforeWaiting(32):進入休眠狀態(tài)前會自動銷毀一個autorelease,然后重新創(chuàng)建一個新的autorelease
- kCFRunLoopExit(128):退出runloop時會自動銷毀最后一個創(chuàng)建的autorelease
為什么 NotificationCenter 要 removeObserver? 如何實現(xiàn)自動 remove?
- 如果不移除的話,萬一注冊通知的類被銷毀以后又發(fā)了通知,程序會崩潰.因為向野指針發(fā)送了消息
- 實現(xiàn)自動remove:通過自釋放機制,通過動態(tài)屬性將remove轉移給第三者,解除耦合,達到自動實現(xiàn)remove
當 TableView 的 Cell 改變時至非,如何讓這些改變以動畫的形式呈現(xiàn)钠署?
這里舉個例子,點擊cell以后以動畫形式改變cell高度
@interface ViewController ()
@property (nonatomic, strong) NSIndexPath *index;
@end
@implementation ViewController
static NSString *ID = @"cell";
- (void)viewDidLoad {
[super viewDidLoad];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
cell.textLabel.text = [NSString stringWithFormat:@"%ld",(long)indexPath.row];
return cell;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 20;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if(self.index == indexPath){
return 120;
}
return 60;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
self.index = indexPath;
[tableView deselectRowAtIndexPath:indexPath animated:TRUE];
// 重點是這2句代碼實現(xiàn)的功能
[tableView beginUpdates];
[tableView endUpdates];
}
為什么 UIScrollView 的滾動會導致 NSTimer 失效?
定時器里面有個runoop mode,一般定時器是運行在defaultmode上但是如果滑動了這個頁面,主線程runloop會轉到UITrackingRunLoopMode中,這時候就不能處理定時器了,造成定時器失效,原因就是runroop mode選錯了,解決辦法有2個,一個是更改mode為NSRunLoopCommonModes(無論runloop運行在哪個mode,都能運行),還有種辦法是切換到主線程來更新UI界面的刷新
為什么當 Core Animation 完成時荒椭,layer 又會恢復到原先的狀態(tài)谐鼎?
因為這些產(chǎn)生的動畫只是假象,并沒有對layer進行改變.那么為什么會這樣呢,這里要講一下圖層樹里的呈現(xiàn)樹.呈現(xiàn)樹實際上是模型圖層的復制,但是它的屬性值表示了當前外觀效果,動畫的過程實際上只是修改了呈現(xiàn)樹,并沒有對圖層的屬性進行改變,所以在動畫結束以后圖層會恢復到原先狀態(tài)
你會如何存儲用戶的一些敏感信息,如登錄的 token
- 使用keychain來存儲,也就是鑰匙串,使用keychain需要導入
Security
框架
自定義一個keychain的類
#import <Security/Security.h>
@implementation YCKKeyChain
+ (NSMutableDictionary *)getKeychainQuery:(NSString *)service {
return [NSMutableDictionary dictionaryWithObjectsAndKeys:
(__bridge_transfer id)kSecClassGenericPassword,(__bridge_transfer id)kSecClass,
service, (__bridge_transfer id)kSecAttrService,
service, (__bridge_transfer id)kSecAttrAccount,
(__bridge_transfer id)kSecAttrAccessibleAfterFirstUnlock,(__bridge_transfer id)kSecAttrAccessible,
nil];
}
+ (void)save:(NSString *)service data:(id)data {
// 獲得搜索字典
NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
// 添加新的刪除舊的
SecItemDelete((__bridge_retained CFDictionaryRef)keychainQuery);
// 添加新的對象到字符串
[keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:data] forKey:(__bridge_transfer id)kSecValueData];
// 查詢鑰匙串
SecItemAdd((__bridge_retained CFDictionaryRef)keychainQuery, NULL);
}
+ (id)load:(NSString *)service {
id ret = nil;
NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
// 配置搜索設置
[keychainQuery setObject:(id)kCFBooleanTrue forKey:(__bridge_transfer id)kSecReturnData];
[keychainQuery setObject:(__bridge_transfer id)kSecMatchLimitOne forKey:(__bridge_transfer id)kSecMatchLimit];
CFDataRef keyData = NULL;
if (SecItemCopyMatching((__bridge_retained CFDictionaryRef)keychainQuery, (CFTypeRef *)&keyData) == noErr) {
@try {
ret = [NSKeyedUnarchiver unarchiveObjectWithData:(__bridge_transfer NSData *)keyData];
} @catch (NSException *e) {
NSLog(@"Unarchive of %@ failed: %@", service, e);
} @finally {
}
}
return ret;
}
+ (void)delete:(NSString *)service {
NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
SecItemDelete((__bridge_retained CFDictionaryRef)keychainQuery);
}
在別的類實現(xiàn)存儲,加載,刪除敏感信息方法
// 用來標識這個鑰匙串
static NSString * const KEY_IN_KEYCHAIN = @"com.yck.app.allinfo";
// 用來標識密碼
static NSString * const KEY_PASSWORD = @"com.yck.app.password";
+ (void)savePassWord:(NSString *)password
{
NSMutableDictionary *passwordDict = [NSMutableDictionary dictionary];
[passwordDict setObject:password forKey:KEY_PASSWORD];
[YCKKeyChain save:KEY_IN_KEYCHAIN data:passwordDict];
}
+ (id)readPassWord
{
NSMutableDictionary *passwordDict = (NSMutableDictionary *)[YCKKeyChain load:KEY_IN_KEYCHAIN];
return [passwordDict objectForKey:KEY_PASSWORD];
}
+ (void)deletePassWord
{
[YCKKeyChain delete:KEY_IN_KEYCHAIN];
}
有用過一些開源組件吧趣惠,能簡單說幾個么狸棍,大概說說它們的使用場景實現(xiàn)。
- AFN:網(wǎng)絡請求
- FMDB:使用數(shù)據(jù)庫
- MJExtension: JSON與Model互轉
- SVProgressHUD:提示HUD
- Masonry:自動布局
- MJRefresh:下拉和上拉刷新
什么時候會發(fā)生 EXC BAD ACCESS 異常味悄?
- 訪問一個僵尸對象草戈,訪問僵尸對象的成員變量或者向其發(fā)消息
- 死循環(huán)
NSNotification 和 KVO 的使用場景?
- KVO使用場景:當一個對象的特定屬性改變的時候傍菇,需要被通知一個或者多個對象的時候
- NSNotification使用場景:跨層級傳遞值,多個對象通知多個對象
使用 Block 時需要注意哪些問題猾瘸?
- 在block內部使用外部指針且會造成循環(huán)引用情況下,需要用
__weak
修飾外部指針
__weak typeof(self) weakSelf = self;
- 在block內部如果調用了延時函數(shù)還使用弱指針會取不到該指針,因為已經(jīng)被銷毀了,需要在block內部再將弱指針重新強引用一下
__strong typeof(self) strongSelf = weakSelf;
- 如果需要在block內部改變外部變量的話,需要在用
__block
修飾外部變量
筆者也寫過一篇block博客
performSelector:withObject:afterDelay: 內部大概是怎么實現(xiàn)的,有什么注意事項么丢习?
- 創(chuàng)建一個定時器,時間結束后系統(tǒng)會使用runtime通過方法名稱(Selector本質就是方法名稱)去方法列表中找到對應的方法實現(xiàn)并調用方法
- 注意事項
- 調用
performSelector:withObject:afterDelay:
方法時,先判斷希望調用的方法是否存在respondsToSelector:
- 這個方法是異步方法,必須在主線程調用,在子線程調用永遠不會調用到想調用的方法
- 調用
使用 NSUserDefaults 時,如何處理布爾的默認值淮悼?(比如返回 NO咐低,不知道是真的 NO 還是沒有設置過)
if([[NSUserDefaults standardUserDefaults] objectForKey:ID] == nil){
NSLog(@"沒有設置");
}
哪些途徑可以讓 ViewController 瘦下來?
- 把 Data Source 和其他 Protocols 分離出來(將UITableView或者UICollectionView的代碼提取出來放在其他類中)
- 將業(yè)務邏輯移到 Model 中(和模型有關的邏輯全部在model中寫)
- 把網(wǎng)絡請求邏輯移到 Model 層(網(wǎng)絡請求依靠模型)
- 把 View 代碼移到 View 層(自定義View)
有哪些常見的 Crash 場景袜腥?
- 訪問了僵尸對象
- 訪問了不存在的方法
- 數(shù)組越界
- 在定時器下一次回調前將定時器釋放,會Crash