天天看點

ios面試題一

什麼是響應鍊,它是怎麼工作的?

這個問題筆者寫過一篇部落格,裡面有對這個問題的詳細解釋

如何通路并修改一個類的私有屬性?

  • 有兩種方法可以通路私有屬性,一種是通過KVC擷取,一種是通過runtime通路并修改私有屬性
  • 建立一個Father類,聲明一個私有屬性name,并重寫description列印name的值,在另外一個類中通過runtime來擷取并修改Father中的屬性
@interface Father ()
@property (nonatomic, copy) NSString *name;
@end
@implementation Father

- (NSString *)description
{
    return [NSString stringWithFormat:@"name:%@",_name];
}

@implementation ViewController

- (void)viewDidLoad {

    [super viewDidLoad];

    Father *father = [Father new];  
    // count記錄變量的數量IVar是runtime聲明的一個宏
    unsigned int count = ;
    // 擷取類的所有屬性變量
    Ivar *menbers = class_copyIvarList([Father class], &count);
    
    for (int i = ; i < count; i++) {
        Ivar ivar = menbers[i];
        // 将IVar變量轉化為字元串,這裡獲得了屬性名
        const char *memberName = ivar_getName(ivar);
        NSLog(@"%s",memberName);
        
        Ivar m_name = menbers[];
        // 修改屬性值
        object_setIvar(father, m_name, @"zhangsan");
        // 列印後發現Father中name的值變為zhangsan
        NSLog(@"%@",[father description]);
    }

}
           

iOS Extension 是什麼?能列舉幾個常用的 Extension 麼?

  • Extension是擴充,沒有分類名字,是一種特殊的分類,類擴充可以擴充屬性,成員變量和方法
  • 常用的擴充是在.m檔案中聲明私有屬性和方法,這裡不知道還哪些,請大家補充

如何把一個包含自定義對象的數組序列化到磁盤?

  • 自定義對象隻需要實作

    NSCoding

    協定即可
- (void)viewDidLoad
{
    [super viewDidLoad];
    
    User *user = [User new];
    Account *account = [Account new];
    NSArray *userArray = @[user, account];
    // 存到磁盤
    NSData * tempArchive = [NSKeyedArchiver archivedDataWithRootObject: userArray];
}
// 代理方法
- (instancetype)initWithCoder:(NSCoder *)coder
{
    self = [super initWithCoder:coder];
    if (self) {
        self.user = [aDecoder decodeObjectForKey:@"user"];
        self.account = [aDecoder decodeObjectForKey:@"account"];
    }
    return self;
}
// 代理方法
-(void)encodeWithCoder:(NSCoder *)aCoder{
    [aCoder encodeObject:self.user forKey:@"user"];
    [aCoder encodeObject:self.account forKey:@"account"];
}
           

Apple Pay 是什麼?它的大概工作流程是怎樣的?

這個筆者也沒有詳細了解過,大家可以百度谷歌一下具體的

iOS 的沙盒目錄結構是怎樣的? App Bundle 裡面都有什麼?

1.沙盒結構

  • Application:存放程式源檔案,上架前經過數字簽名,上架後不可修改
  • Documents:常用目錄,iCloud備份目錄,存放資料,這裡不能存緩存檔案,否則上架不被通過
  • Library
    • Caches:存放體積大又不需要備份的資料,SDWebImage緩存路徑就是這個
    • Preference:設定目錄,iCloud會備份設定資訊
  • tmp:存放臨時檔案,不會被備份,而且這個檔案下的資料有可能随時被清除的可能

2.App Bundle 裡面有什麼

  • Info.plist:此檔案包含了應用程式的配置資訊.系統依賴此檔案以擷取應用程式的相關資訊
  • 可執行檔案:此檔案包含應用程式的入口和通過靜态連接配接到應用程式target的代碼
  • 資源檔案:圖檔,聲音檔案一類的
  • 其他:可以嵌入定制的資料資源

iOS 的簽名機制大概是怎樣的?

假設,我們有一個APP需要釋出,為了防止中途篡改APP内容,保證APP的完整性,以及APP是由指定的私鑰發的。首先,先将APP内容通過摘要算法,得到摘要,再用私鑰對摘要進行加密得到密文,将源文本、密文、和私鑰對應的公鑰一并釋出即可。那麼如何驗證呢?

驗證方首先檢視公鑰是否是私鑰方的,然後用公鑰對密文進行解密得到摘要,将APP用同樣的摘要算法得到摘要,兩個摘要進行比對,如果相等那麼一切正常。這個過程隻要有一步出問題就視為無效。

iOS 7的多任務添加了哪兩個新的 API? 各自的使用場景是什麼?

  • 背景擷取(Background Fetch):背景擷取使用場景是使用者打開應用之前就使app有機會執行代碼來擷取資料,重新整理UI。這樣在使用者打開應用的時候,最新的内容将已然呈現在使用者眼前,而省去了所有的加載過程。
  • 推送喚醒(Remote Notifications):使用場景是使裝置在接收到遠端推送後讓系統喚醒裝置和我們的背景應用,并先執行一段代碼來準備資料和UI,然後再提示使用者有推送。這時使用者如果解鎖裝置進入應用後将不會再有任何加載過程,新的内容将直接得到呈現。

UIScrollView 大概是如何實作的,它是如何捕捉、響應手勢的?

  • 我對UIScrollView的了解是frame就是他的contentSize,bounds就是他的可視範圍,通過改變bounds進而達到讓使用者誤以為在滾動,以下是一個簡單的UIScrollView實作

在頭檔案定義一個contentSize屬性

@interface MyScrollView : UIView
@property (nonatomic) CGSize contentSize;
@end
           
@implementation MyScrollView
- (instancetype)initWithFrame:(CGRect)frame{
    self = [super initWithFrame:frame];
    if (self == nil) {
        return nil;
    }
    // 添加一個滑動手勢
    UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(panGesture:)];
    [self addGestureRecognizer:pan];
    return self;
}

- (void)panGesture:(UIPanGestureRecognizer *)gestureRecognizer{
    // 改變bounds
    CGPoint translation = [gestureRecognizer translationInView:self];
    CGRect bounds = self.bounds;
    
    CGFloat newBoundsOriginX = bounds.origin.x - translation.x;
    CGFloat minBoundsOriginX = ;
    CGFloat maxBoundsOriginX = self.contentSize.width - bounds.size.width;
    bounds.origin.x = fmax(minBoundsOriginX, fmin(newBoundsOriginX, maxBoundsOriginX));
    
    CGFloat newBoundsOriginY = bounds.origin.y - translation.y;
    CGFloat minBoundsOriginY = ;
    CGFloat maxBoundsOriginY = self.contentSize.height - bounds.size.height;
    bounds.origin.y = fmax(minBoundsOriginY, fmin(newBoundsOriginY, maxBoundsOriginY));
    
    self.bounds = bounds;
    [gestureRecognizer setTranslation:CGPointZero inView:self];
}
           
  • 第二個問題個人了解是解決手勢沖突,對自己添加的手勢進行捕獲和響應
// 讓UIScrollView遵守UIGestureRecognizerDelegate協定,實作這個方法,在這裡方法裡對添加的手勢進行處理就可以解決沖突
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
           

Objective-C 如何對已有的方法,添加自己的功能代碼以實作類似記錄日志這樣的功能?

  • 這題目主要考察的是runtime如何交換方法

先在分類中添加一個方法,注意不能重寫系統方法,會覆寫

+ (NSString *)myLog
{
    // 這裡寫列印行号,什麼方法,哪個類調用等等
}
           

然後交換方法

// 加載分類到記憶體的時候調用
+ (void)load
{
    // 擷取imageWithName方法位址
    Method description = class_getClassMethod(self, @selector(description));

    // 擷取imageWithName方法位址
    Method myLog = class_getClassMethod(self, @selector(myLog));

    // 交換方法位址,相當于交換實作方式
    method_exchangeImplementations(description, myLog);
}
           

+load 和 +initialize 的差別是什麼?

  • +(void)load;
    • 當類對象被引入項目時, runtime 會向每一個類對象發送 load 消息

      load 方法會在每一個類甚至分類被引入時僅調用一次,調用的順序:父類優先于子類, 子類優先于分類

    • load 方法不會被類自動繼承
  • +(void)initialize;
    • 也是在第一次使用這個類的時候會調用這個方法

如何讓 Category 支援屬性?

  • 使用runtime可以實作

頭檔案

@interface NSObject (test)
 
@property (nonatomic, copy) NSString *name;
 
@end
           

.m檔案

@implementation NSObject (test)
// 定義關聯的key
static const char *key = "name";
- (NSString *)name
{
    // 根據關聯的key,擷取關聯的值。
    return objc_getAssociatedObject(self, key);
}
- (void)setName:(NSString *)name
{
    // 第一個參數:給哪個對象添加關聯
    // 第二個參數:關聯的key,通過這個key擷取
    // 第三個參數:關聯的value
    // 第四個參數:關聯的政策
    objc_setAssociatedObject(self, key, name, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
           

NSOperation 相比于 GCD 有哪些優勢?

  • 提供了在 GCD 中不那麼容易複制的有用特性。
  • 可以很友善的取消一個NSOperation的執行
  • 可以更容易的添加任務的依賴關系
  • 提供了任務的狀态:isExecuteing, isFinished.

strong / weak / unsafe_unretained 的差別?

  • weak隻能修飾OC對象,使用weak不會使計數器加1,對象銷毀時修飾的對象會指向nil
  • strong等價與retain,能使計數器加1,且不能用來修飾資料類型
  • unsafe_unretained等價與assign,可以用來修飾資料類型和OC對象,但是不會使計數器加1,且對象銷毀時也不會将對象指向nil,容易造成野指針錯誤

如何為 Class 定義一個對外隻讀對内可讀寫的屬性?

在頭檔案中将屬性定義為

readonly

,在.m檔案中将屬性重新定義為

readwrite

Objective-C 中,meta-class 指的是什麼?

meta-class 是 Class 對象的類,為這個Class類存儲類方法,當一個類發送消息時,就去那個類對應的meta-class中查找那個消息,每個Class都有不同的meta-class,所有的meta-class都使用基類的meta-class(假如類繼承NSObject,那麼他所對應的meta-class也是NSObject)作為他們的類

UIView 和 CALayer 之間的關系?

  • UIView顯示在螢幕上歸功于CALayer,通過調用drawRect方法來渲染自身的内容,調節CALayer屬性可以調整UIView的外觀,UIView繼承自UIResponder,CALayer不可以響應使用者事件
  • UIView是iOS系統中界面元素的基礎,所有的界面元素都繼承自它。它内部是由Core Animation來實作的,它真正的繪圖部分,是由一個叫CALayer(Core Animation Layer)的類來管理。UIView本身,更像是一個CALayer的管理器,通路它的根繪圖和坐标有關的屬性,如frame,bounds等,實際上内部都是通路它所在CALayer的相關屬性
  • UIView有個layer屬性,可以傳回它的主CALayer執行個體,UIView有一個layerClass方法,傳回主layer所使用的類,UIView的子類,可以通過重載這個方法,來讓UIView使用不同的CALayer來顯示

+[UIView animateWithDuration:animations:completion:] 内部大概是如何實作的?

  • animateWithDuration:這就等于建立一個定時器
  • animations:這是建立定時器需要實作的SEL
  • completion:是定時器結束以後的一個回調block

以上隻是自己的了解,不一定正确,有對這個有研究的朋友請告知下

什麼時候會發生「隐式動畫」?

當改變CALayer的一個可做動畫的屬性,它并不能立刻在螢幕上展現出來.相反,它是從先前的值平滑過渡到新的值。這一切都是預設的行為,你不需要做額外的操作,這就是隐式動畫

如何處理異步的網絡請求?

異步請求:會單獨開一個線程去處理網絡請求,主線程依然處于可互動狀态,程式運作流暢

// POST請求
    NSString *urlString = @"www.baidu.com";
    // 建立url對象
    NSURL *url = [NSURL URLWithString:urlString];
    // 建立請求
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:];
    // 建立參數字元串對象
    NSString *parmStr = [NSString stringWithFormat:@"參數"];
    // 将字元串轉換為NSData對象
    NSData *data = [parmStr dataUsingEncoding:NSUTF8StringEncoding];
    [request setHTTPBody:data];
    [request setHTTPMethod:@"POST"];
    // 建立異步連接配接
    [NSURLConnection connectionWithRequest:request delegate:self];
           

然後實作代理方法

// 伺服器接收到請求時
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
}
// 當收到伺服器傳回的資料時觸發, 傳回的可能是資源片段
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
}
// 當伺服器傳回所有資料時觸發, 資料傳回完畢
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
}
// 請求資料失敗時觸發
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
    NSLog(@"%s", __FUNCTION__);
}
           

frame 和 bounds 的差別是什麼?

  • frame相對于父視圖,是父視圖坐标系下的位置和大小。bounds相對于自身,是自身坐标系下的位置和大小。
  • frame以父控件的左上角為坐标原點,bounds以自身的左上角為坐标原點

如何把一張大圖縮小為1/4大小的縮略圖?

let data = UIImageJPEGRepresentation(image, 0.25)

有一句話叫做三人行必有我師,其實做為一個開發者,有一個學習的氛圍跟一個交流圈子特别重要這是一個我的iOS交流群681503716,請備注編号朝拜,大牛歡迎入駐,正在求職的也可以加入,大家一起交流學習,話糙理不糙,互相學習,共同進步,一起加油吧。)