iOS 每天一道面試題

weixin_34378969發表於2017-03-24

同為菜逼,共同努力。

1.nil Nil NULL NSNull 區別。

nil:指向oc中物件的空指標,針對物件。

Nil:指向oc中類的空指標,針對類。

NULL:指向其他型別的空指標,如一個c型別的記憶體指標,基本資料型別為空,基本型別。

NSNull:在集合物件中,表示空值的物件。

參考部落格這是我發現寫的比較詳細的部落格.

2.你是否接觸過oc中的反射機制?簡單聊一下概念和使用.

    //    • class反射
    //    • 通過類名的字串形式例項化物件
    Class class1 = NSClassFromString(@"UILabel");
    id label = [[class1 alloc ]init];
    NSLog(@"label = %@",label);
    //    • 將類名變為字串
    Class class2 =[UILabel class];
    NSString *className = NSStringFromClass(class2);
    NSLog(@"className = %@",className);

    Student *stu = [[Student alloc] init];
    //    • SEL的反射
    //    • 通過方法的字串形式例項化方法
    SEL selector = NSSelectorFromString(@"setName:");
    [stu performSelector:selector withObject:@"GanMaoShen"]; //注意如果有兩個引數,使用兩個withObject:引數;
    NSLog(@"stu.name =%@",stu.name);
    //    • 將方法變成字串
    NSString *select =  NSStringFromSelector(@selector(testVoidFuncWithTestParam:));
    NSString *select2 =  NSStringFromSelector(_cmd);
    NSLog(@"select =%@ select2 = %@",select,select2);
2017-03-27 20:19:07.658 test[10559:3059755] label = <UILabel: 0x7fdcae00fed0; frame = (0 0; 0 0); userInteractionEnabled = NO; layer = <_UILabelLayer: 0x6000002834d0>>
2017-03-27 20:19:07.659 test[10559:3059755] className = UILabel
2017-03-27 20:19:07.659 test[10559:3059755] stu.name =GanMaoShen
2017-03-27 20:19:07.659 test[10559:3059755] select =testVoidFuncWithTestParam: select2 = viewDidLoad

3.Block的傳值,傳址,記憶體管理,迴圈引用(retain cycle)。(狠補了一下block的知識,發現block中很多知識點,所以還是要弄透)

兩篇很好的block基礎部落格
block的用法,定義.
block兩個介面的傳值.

void test1()
{
  int a = 10;
}
void test2()
{
    __block int a = 10;
}
void test3()
{
    static int a = 10;
}
int a = 10;
void test4()
{
}
總結:block中只有普通區域性變數(test1)是傳值,其他情況(test2,test3,test4)都是傳址。
#block的記憶體管理
ARC下:
- block可以使用copy和strong,並且是一個物件。

#Block如果沒有引用外部變數
儲存在全域性區(MRC/ARC一樣)
#Block如果引用外部變數
ARC儲存在 堆區; MRC儲存在 棧區必須用copy修飾block;

推薦部落格深入淺出-iOS Block原理和記憶體中位置

block迴圈引用
1.如果block程式碼塊的內部,使用了外面的強引用物件,block程式碼塊的內部會自動產生一個強引用,引用著該物件,不會銷燬,造成迴圈引用.
解決:下面程式碼在block外部實現.
__weak typeof(self) weakSelf = self; 
#define WeakSelf(type)  __weak typeof(type) weak##type = type;
2.但是如果在block內部使用延時操作的還使用弱指標的話會取不到該弱指標,需要在block內部再將弱指標強引用一下.
__strong typeof(self) strongSelf = weakSelf;
#define StrongSelf(type)  __strong typeof(type) strong##type = weak##type;

關於迴圈引用很好的部落格Swift與OC真正去理解Block解決迴圈引用的技巧

4.如何在@category和@protocol中新增@property

首先你要知道category和protocol和作用和區別,同時回顧這道題的同時,同時回顧extension 和category。
extension看起來很像一個匿名的category,但是extension和有名字的category幾乎完全是兩個東西。 extension在編譯期決議,它就是類的一部分,在編譯期和標頭檔案裡的@interface以及實現檔案裡的@implement一起形成一個完整的類,它伴隨類的產生而產生,亦隨之一起消亡。extension一般用來隱藏類的私有資訊,你必須有一個類的原始碼才能為一個類新增extension,所以你無法為系統的類比如NSString新增extension。
更深入一點的話我推薦這個帖子。iOS 類別不能新增屬性原理?

@dynamic 和 @synthesize的區別:
在@implementation 中通過@dynamic xxx 告訴編譯器、xxx屬性的setter、getter方法由開發者自己來生成
@ synthesize xxx = _xxx; 告訴編譯器、xxx屬性的setter、getter方法由編譯器來生成、同時用_xxx 來合成 成員變數

好,步入正題。

4.1@protocol中新增property

在protocol中新增property時,其實就是宣告瞭 getter 和 setter 方法,在實現這個protocol協議的類中,我們要自己手動新增例項變數,並且需要實現setter/getter方法,實現setter/getter方法有兩種方式,一種是自動生成(@synthesize) ,另一種是手動生成(@dynamic)此時又有了擴充問題(@synthesize和@dynamic的作用 見 題5)

@protocol PersonDelegate <NSObject>
@property (nonatomic, copy) NSString *name;
@end
//personn類
@interface Person : NSObject
@end
#import "Person.h"
@interface Student : NSObject <PersonDelegate>
- (void)testLog;
@end
#import "Student.h"

@implementation Student
//自動實現setter和getter方法
@synthesize name;

- (void)testLog {
    NSLog(@"self.name=%@",self.name);
}

@end

手動實現setter和getter

#import "Person.h"
@interface Student2 : NSObject <PersonDelegate>
{
    //宣告一個例項變數
    NSString *_name;
}
- (void)testLog;
@end

#import "Student2.h"

@implementation Student2
@dynamic name;
- (void)testLog {
    NSLog(@"self.name=%@",self.name);
}
- (void)setName:(NSString *)name
{
    _name = name;
}
- (NSString *)name
{
    return _name;
}
@end
    Student *stu1 = [Student new];
    stu1.name = @"testName";
    [stu1 testLog];
    Student2 *stu2 = [Student2 new];
    stu2.name = @"testName";
    [stu2 testLog];

關於category實現property主要是利用runtime的關聯方法(mjrefresh中也有用到)。

objc_setAssociatedObject   objc_getAssociatedObject
@interface Person (Test)
@property (nonatomic, copy) NSString *tmpName;
- (void)testLog;
@end
#import "Person+Test.h"
#import <objc/runtime.h>

@implementation Person (Test)
- (void)setTmpName:(NSString *)tmpName
{
    objc_setAssociatedObject(self, @selector(tmpName), tmpName, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (NSString *)tmpName
{
    return objc_getAssociatedObject(self, @selector(tmpName));
}
- (void)testLog {
    NSLog(@"self.name=%@",self.tmpName);
}
@end
    Person *p1 = [Person new];
    p1.tmpName = @"tmpName";
    [p1 testLog];

當然還有一種利用臨時變數的方法完成新增屬性的方法。參考部落格
iOS Category 和 Protocol 中的 Property 你們真的會了麼?

相關文章