The original link: kukumalucn. Making. IO/blog / 2018/1…

preface

It’s interesting to see this code in the group:

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    dispatch_async(dispatch_get_global_queue(0.0), ^ {NSLog(@ "1");
        [self performSelector:@selector(test) withObject:nil afterDelay:0];
        NSLog(@ "2");
    });
}
- (void)test
{
    NSLog(@ "3");
}
Copy the code

What is the result of executing this code? Should I print “1, 2”, “1, 3, 2”, or “1, 2, 3”?

content

1. Question exploration

This is an interesting interview question about runloop. The answer is to print only: “1, 2”. The gods of the cause group have the answer:

Because [self performSelector:@selector(test) withObject:nil afterDelay:.0] is actually a timer inside a runloop, but because of the child thread, the runloop is not enabled by default.

In addition to runloop, there are also multithreading issues for those interested. We can explain this by reading the apple API notes carefully:

If you want to execute the -test method, the comment also provides a solution:

[self performSelectorOnMainThread:@selector(test) withObject:nil waitUntilDone:YES];
Copy the code

In fact, for the above logic, the simpler is:

[self performSelector:@selector(test) withObject:nil];
Copy the code

2. Triggered thinking

2.1. Don’t be lazy

The reason to mention the above questions, in addition to the interview “examination point”, in fact, in the usual development process should also pay attention to the rigor of their own code. I find myself reading other people’s code and seeing the same thing written, even in well-known tripartite libraries like YYText:

[self performSelector:@selector(test) withObject:nil afterDelay:0];
Copy the code

The people who wrote this code just wanted to execute a method at once with a selector, and delay wasn’t their requirement, so why bother? A big part of the reason, most likely, is that we are “spoiled” by xcode’s autoprompt:

After all, when you write code, the list of hints is just arranged according to the API similarity, many people see their need to directly enter, do not need delay, directly write 0, anyway, “the same”…… This is a myth. The API that looks very similar is not the same, but very different:

  • The method we use to perform is the nsobject. h header:

  • Nsrunloop. h ¶

  • To call the main thread, use NSThread. H:

Although they are both methods of NSObject or classification supplements, they actually belong to different modules.

2.2. More profound reasons

But the writers of “YYText” are unlikely to make such silly mistakes, and there may be a deeper reason:

Many of us will always be bothered by the above warnings, and most of us will solve this problem by using a facial-like method to block the warnings, which is simple but actually risky:

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
//code
#pragma clang diagnostic pop
Copy the code

In addition to IMP or NSInvocation which is “high end”, more often when the method has no return value, or when we do not need the return value, we can use:

[self performSelector:@selector(test) withObject:nil afterDelay:0];
Copy the code

This way to avoid warnings, if you look at the three comparisons above, you can see that the last two apis, which are also performSelector, return no value, and this is actually based on the official annotation:

But you also want to notice, the official suggestion is very rigorous, is to use performSelectorOnMainThread, rather than delay0 way, as for the reason, we returned to the article at the beginning of a discussion.

conclusion

From the seemingly pointless exploration above, we can still learn a profound lesson: “Apple bully” is very careful, read the API comments, always right.


In this paper, the author: lam Wei this article links: kukumalucn. Making. IO/blog / 2018/1… Copyright Notice: All articles on this blog are licensed under CC BY-NC-ND 4.0 unless otherwise stated. Reprint please indicate the source!