面接問題ライブラリDemo_01
5801 ワード
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中:
isa
ポインタが指すClassからメソッドトピックに戻り、
Father
のようなインスタンスメソッド(- responseToSelector
)メッセージが送信されると、isa
、つまりFatherメタオブジェクトから探します.メタクラスのメソッドはすべてクラスメソッドなので、- 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が実行する順序は、次のように見えます.ネットワーク要求はすぐに戻り、コールバック関数は一般的に次のように実行されます.
//
dispatch_async(dispatch_get_main_queue(), ^{
if (self.completionBlock) self.completionBlock();
});
こうなりました
したがって、sleepが終了すると、プライマリスレッドは呼び出し順序を維持します.
このとき、
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同期の実行が完了するのを待つ.