Xcode fails to recognize dispatch_once block as correct - ios

I'm using this common code style in multiple different places throughout my codebase, however in one location, Xcode all of a sudden doesn't like it:
static dispatch_once_t once;
dispatch_once(&once, ^{
...
});
It shows the following error:
Incompatible block pointer types passing 'void *(^)(void)' to parameter of type 'dispatch_block_t _Nonnull' (aka 'void (^)(void)')
The style is exactly the same as in other parts of the code, so I'm kind of at a loss as to what exactly is the issue here.
It also has the following error at the closing brace of the block:
Control may reach end of non-void block

Upon further inspection, there was an instance in the block where I had return nil; (I had added the dispatch code retroactively)
Because of that return statement XCode assumed the block had a void * return type which didn't match the expected block signature for dispatch_once, hence the error at the beginning of the block instead of where the problem was.

Related

dispatch_once what means "Always call this function before using or testing any variables that are initialized by the block." in documentation?

Apple documentation [1]
https://developer.apple.com/reference/dispatch/1447169-dispatch_once
in "Discussion" section says:
This function is useful for initialization of global data (singletons)
in an application. Always call this function before using or testing
any variables that are initialized by the block.
If called simultaneously from multiple threads, this function waits
synchronously until the block has completed.
The predicate must point to a variable stored in global or static
scope. The result of using a predicate with automatic or dynamic
storage (including Objective-C instance variables) is undefined.
What does following phrase means?
Always call this function before using or testing
any variables that are initialized by the block.
Could you kindly show short example of code when I must comply with this requirement?
My thoughts:
this NOT about block like in following example:
+(instancetype)sharedInstance {
static id sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
because of I can not (for sure) use sharedInstance initialized by block before call to dispatch_once. Because dispatch_once calling this block! So what is the block, that Apple documentation warns us about?
This simply means that if you initialize sharedInstance inside the block passed to dispatch_once, you need to make sure that dispatch_once is called prior to accessing sharedInstance for the first time. In other words, if you access any variable that is set for the first time by dispatch_once, the value that you read may be uninitialized.

TMCache - using Blocks to Monitor Cache Events

From the documentation:
/**
A block to be executed just after an object is added to the cache. This block will be excuted within
a barrier, i.e. all reads and writes are suspended for the duration of the block.
*/
#property (copy) TMMemoryCacheObjectBlock didAddObjectBlock;
I'm trying to make use of this to print a message when objects are added to the cache. My attempt so far:
[[_timedCache memoryCache] setDidAddObjectBlock:^{
NSLog(#"added something to cache");
}];
This gives a "parameter type mismatch" compiler error however. I'm fairly new to Objective-C and am probably doing something naive here. Any suggestions?
TMemoryCahceObjectBlock has the following signature: (TMMemoryCache *cache, NSString *key, id object), which your block doesn't have. Change the signature of your block and you are golden.

Does compiler saves argument of a function?

I have a function which is loading image by index in another thread using GCD .
So lets assume this :
-(void)loadMainImageToIndex:(long)index
{
NSDictionary *dic=[mainData objectAtIndex:index];
NSString *userImageUrl=[dic objectForKey:#"url"];
NSURL *userUrl=[NSURL URLWithString:userImageUrl];
[self downloadImageWithURL:userUrl completionBlock:^(BOOL succeeded, NSData *tdata)
{
if (succeeded)
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^
{
//do something here
dispatch_async(dispatch_get_main_queue(), ^
{
//do something here that uses the index argument
And i call this function 3 times :
[self loadMainImageToIndex:0];
[self loadMainImageToIndex:1];
[self loadMainImageToIndex:2];
Question is, when the first call will end the thread operation , and will got to the point :
dispatch_async(dispatch_get_main_queue()
Will he see in there index=0 , or will he see the last index was called (==2) ?
Question is, does he copy the whole function so when he finishes he can remember the argument that started the method ?
Another thing, does calling it 3 times at the same time, is a bad practice ?
Thanks.
Short version: there's no problem here. You're doing fine and it'll behave like you would expect (each block will have the correct value).
Longer version:
-(void)loadMainImageToIndex:(long)index
Every call to this method will push a fresh copy of index onto the stack. It will be popped (destroyed) when the method returns. Even if this method is called many times in parallel (on different threads), each will have its own copy of index on its own stack. Local variables and arguments are private to a each call of a method or function.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^
The creation of a block here "captures" (copies) all the variables that it discovers within the block. That includes index because it's used by:
dispatch_async(dispatch_get_main_queue(), ^
So, there's no problem here. Your block that is sent to the main queue will have its own copy of index, which it made at the time the block was created. The enclosing block also made a copy of index at the time it was created, and the method made a copy of the value that was passed to it as index.
Note that "when a block is created" is the point at which the ^{} is evaluated, not the point that dispatch_ functions are called. Those functions accept a block, they don't create the block. It is completely legal (and common) to create a block and store it in a variable and later pass that block to something else. The block will capture (copy) its variables at the point that it's created. This concept is called a closure.

ios about pass by reference

From my current understanding, the recommended way (with ARC enabled) of 'pass by reference' is like:
-(void)somefunc:(someclass **)byref;
// and 'someclass **' should be inferred to 'someclass * __autoreleasing *'
// am i right?
//or we could just explicitly define it like
-(void)somefunc:(someclass * __autoreleasing *)byref;
However, from the answer to this thread, Handling Pointer-to-Pointer Ownership Issues in ARC.
It seems -(void)somefunc:(someclass *__strong *)byref could do the trick as well (in demo2 of above link).
1.-(void)somefunc:(someclass * __autoreleasing *)byref;
2.-(void)somefunc:(someclass *__strong *)byref
For the first one, as documented by Apple it should be implicitly rewritten by compiler like this:
NSError * __strong error;
NSError * __autoreleasing tmp = error;
BOOL OK = [myObject performOperationWithError:&tmp];
error = tmp;
It seems the second one has a better performance? Because it omits the process of 'assign the value back' and 'autoreleasing'. But I rarely see functions declared like this. Is it a better way to use the second function to do the 'pass by reference' job?
Any suggestion or explanation? Thanks in advance.
the second function isnt thread-safe / 'delay safe'. the first one is more correct.
same reason as to why blocks capture params and performSelector retains the object.
imagine the caller fA allocs a strong reference to A and then calls an ASYNC function fB.
fA is done, fB not yet called.... so who retains A in the meantime?

iOS - Deal with Async task that point to a deallocated variable

I'm calling an asynchronous function from my controller and I pass to it a reference to an error variable, let's say:
NSError *err=nil;
[self myAsyncTask:&err];
if the controller get deallocated, the err variable does not exist anymore, so the app crash with a BAD_ACCESS error (because the function try to change the value of the err variable). How can I deal with that?
Notice that none of the built-in framework methods use pass by reference error reporting with asynchronous calls - they all use delegation or blocks to communicate error status. Using blocks, your API could be written to be used like:
[self doAsyncTaskWithErrorHandler: ^(NSError *error) {
//Handle error
}];
The method signature could look like
- (void)doAsyncTaskWithErrorHandler:(void (^)(NSError *error))errorHandler;
And in the implementation, where you used to do *error = someError; do something like:
NSError *error = ...;
if (errorHandler) {
errorHandler(error);
}
If I'm not mistaken this isn't really an issue with object lifetime though - if the stack frame is popped before the error is set then the pattern in the question would likely cause a crash as well.
How can I deal with that?
If you have an asynchronous function in process, you have to ensure that any variables that it uses remain valid until that function completes. Objective-C's memory management lends itself nicely to this -- a method like your -myAsyncTask can retain its arguments until it no longer needs them. That way, even if the controller (to use your word) is deallocated, the objects referred to by the variables will remain valid.
Another way to do it is to use a block for the async functionality. Blocks automatically retain the resources that they use, so they effectively solve this problem for you.

Resources