面接問題ライブラリDemo_01


 1. ?
- ()init {
     self= [super init];
     if(self) {
        NSLog(@"%@", NSStringFromClass([self class]));
        NSLog(@"%@", NSStringFromClass([super class]));
     }
     return self;
}

result:都出力"Son"解釈:objc中のsuperはコンパイラ識別子であり、selfのように1つのオブジェクトではなく、superへのメソッドに遭遇するとobjc_msgSendSuper(...)に変換され、パラメータ中のオブジェクトはselfであるため、親から継承チェーンに沿って- classというメソッドを探し、最後にNSObject(overrideがなければ)で見つけられ、このとき[self class]と[super class]は等価になった.

2.次のコードは間違っていますか?警告?それとも正常に何を出力しますか?

Father *father = [Father new];
BOOL b1 = [father responseToSelector:(responseToSelector:)];
BOOL b2 = [Father responseToSelector:(responseToSelector:)];
NSLog(@"%d,%d", b1, b2);

result:すべて出力"1"(YES)解釈:objc中:
  • インスタンスオブジェクトもClassもidタイプのオブジェクト(Classもオブジェクト)
  • である.
  • インスタンスオブジェクトのisaはそのClassを指し(すべてのマイナス記号メソッドを格納)、Classオブジェクトのisaはメタクラスを指す(すべてのプラス記号メソッドを格納)
  • .
  • が1つのオブジェクト(idタイプ)にメッセージを送信する場合、いずれもそのオブジェクトのisaポインタが指すClassからメソッド
  • を探す.
    トピックに戻り、Fatherのようなインスタンスメソッド(- responseToSelector)メッセージが送信されると、
  • は、そのisa、つまりFatherメタオブジェクトから探します.メタクラスのメソッドはすべてクラスメソッドなので、
  • は自然に見つかりません.
  • は、継承チェーンに沿って親NSObjectメタクラスから検索され、
  • は依然として存在しない.
  • objcのこの設計は、NSObjectのメタクラスの親クラスがNSObjectクラス(すなわち、私たちがよく知っているNSObjectクラス)であるため、すべてのインスタンスメソッドがあるため、- responseToSelector
  • を見つけた.
    補足:NSObjectクラスのすべてのインスタンスメソッド は、+ resonseToSelectorのようなクラスメソッド(少なくともオープンソースのコードから見ることができる)を実装しているが、公開されたAPIではなく、本当にそうであれば、上から2番目のステップまでこのメソッドを見つけることができる.再補足:NSObject以外のselectorは無効です.

    3.要求はすぐに実行されますが、completionBlockは長い間設定されていません。まだ実行できますか?

    ...
    //  
    [request startAsync]; //  , completionBlock
    sleep(100); // sleep , 
    [request setCompletionBlock:^{
        NSLog(@"Can I be printed?");
    }];
    ...

    result:解釈可能(条件付き)解釈:解釈を容易にするために,gcdの2つの線形queue:main queueとback queueを考慮した.
    コードがsleep(100)に実行されると、この2つのqueueが実行する順序は、次のように見えます.
  • main: *— sleep ————————-> | —setCompletionBlock—>
  • back: *— network —->

  • ネットワーク要求はすぐに戻り、コールバック関数は一般的に次のように実行されます.
    //  
    dispatch_async(dispatch_get_main_queue(), ^{
      if (self.completionBlock) self.completionBlock();
    });

    こうなりました
  • main: *—-sleep—-> | —setCompletionBlock—> | —invoke completionBlock—->
  • back: *

  • したがって、sleepが終了すると、プライマリスレッドは呼び出し順序を維持します.
  • main: *—setCompletionBlock—> | —invoke completionBlock—->

  • このとき、completionBlockの実行はsetCompletionBlock以降であるため、通常のコールバックが可能である.
    注意:この説明には制限条件があります.次の方法でコールバックすると、状況が異なります.
    //  
    if (self.completionBlock) {
      dispatch_async(dispatch_get_main_queue(), ^{
        self.completionBlock();
    });

    4.IBを使わない場合、次のようにするのは問題がありますか?
    - (void)viewDidLoad {
      [super viewDidLoad];
      CGRect frame = CGRectMake(0, 0, self.view.bounds.size.width * 0.5, self.view.bounds.size.height * 0.5);
      UIView *view = [[UIView alloc] initWithFrame:frame];
      [self.view addSubview:view];
    }

    解釈:IBを使用しないで手動でViewControllerを作成する時、viewDidLoadの中で位置の初期化を行っていないで、もとは何度もこの小さい穴に出会ったことがあって、外部がこのvcを作成する時:
    TestViewController *vc = [[TestViewController alloc] init];
    vc.view.frame = CGRectMake(0, 0, 100, 100);
    ViewControllerのview初期化の概要は次のとおりです.
    - (UIView *)view {
      if (!_view) {
        [self loadView];
        [self viewDidLoad];
      }
    }

    したがって、外部でvc.view.frame = CGRectMake(0, 0, 100, 100);という言葉が実行されると、付与操作が実行される前にviewDidLoadが呼び出されるので、viewDidLoadでview frameの値は設定値ではなくデフォルト値(windowのサイズ)となる.
    注意:IBロードを使用する場合もこのようなことが起こりますが、一般的にはIBにプリセット値があります.

    5.次のコードは何を出力しますか?

    - (void)viewDidLoad {
        [super viewDidLoad];
    
        NSLog(@"1");
        dispatch_sync(dispatch_get_main_queue(), ^{
            NSLog(@"2");
        });
        NSLog(@"3");
    }

    result:出力1以降のプログラムデッドロック
    説明:dispatch_sync文書に記載されています.
    Calls to dispatch_sync() targeting the current queue will result in dead-lock. Use of dispatch_sync() is also subject to the same multi-party dead-lock problems that may result from the use of a mutex. Use of dispatch_async() is preferred.syncから現在のスレッドへのblockはデッドロックを引き起こすので、ログが1を出すとメインスレッドはデッドロック状態になり、実行を続行しません.その原因を究明するにはdispatch_を見なければならない.syncが行うことは、1つのblockをqueueに挿入することであり、asyncとは異なりません.syncはこのblockの実行が完了するまで呼び出しポイントに戻って実行を継続するのを待っていますが、このblockの実行はviewDidLoadのdispatch_に依存しています.sync呼び出しの終了により、ループ待ちが発生し、デッドロックが発生します.
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            NSLog(@"=================1");
            dispatch_sync(dispatch_get_main_queue(), ^{
                NSLog(@"=================2");
            });
            NSLog(@"=================3");
        });
        
        
        NSLog(@"========== ");
        while (1) {
        }
        NSLog(@"==========2 ");
    }

    result:
    =================1
    ========== 

    説明:
    GCD Queueは3種類に分けられます.
    1,The main queue:プライマリ・キュー、プライマリ・スレッドはキューにあります.
    2,Global queues:グローバル同時キュー.
    3,ユーザキュー:関数dispatch_queue_createで作成されたカスタムキュー
     
    dispatch_syncとdispatch_asyncの違い:
    dispatch_async(queue,block)async非同期キュー、dispatch_async関数はすぐに戻り、blockはバックグラウンドで非同期で実行されます.
    dispatch_sync(queue,block)sync同期キュー、dispatch_sync関数はすぐに返されず、現在のスレッドをブロックし、block同期の実行が完了するのを待つ.