Objective-C Block Syntax - objective-c

Obj-C blocks are something I'm just using for the first time recently. I'm trying to understand the following block syntax:
In the header file:
#property (nonatomic, copy) void (^completionBlock)(id obj, NSError *err);
In the main file:
-(void)something{
id rootObject = nil;
// do something so rootObject is hopefully not nil
if([self completionBlock])
[self completionBlock](rootObject, nil); // What is this syntax referred to as?
}
I appreciate the assistance!

Blocks are Objects.
In your case inside the method you are checking if the block is not nil and then you are calling it passing the two required arguments ...
Keep in mind that blocks are called in the same way a c function is ...
Below i have split the statement in two to let you understand better :
[self completionBlock] //The property getter is called to retrieve the block object
(rootObject, nil); //The two required arguments are passed to the block object calling it

Its a block property, you can set a block at runtime.
Here is the syntax to set
As it is void type, so within the class you can set a method by following code
self.completionBlock = ^(id aID, NSError *err){
//do something here using id aID and NSError err
};
With following code you can call the method/block set previously.
if([self completionBlock])//only a check to see if you have set it or not
{
[self completionBlock](aID, nil);//calling
}

Related

How to invoke an Objective-C block obtained at runtime?

I'm trying to write a mock of HKHealthStore. In the stubbed executeQuery: I need to call the result handler block of a HKSampleQuery instance passed to it. The block is private so I need to get it at runtime. This is what I have so far:
- (void)executeQuery:(HKQuery *)query {
NSAssert([query isKindOfClass:HKSampleQuery.class], #"Mock executeQuery: not implemented yet for other query types than HKSampleQuery");
HKSampleQuery *sampleQuery = (HKSampleQuery *)query;
NSMutableArray<HKObject *> *queryResults = [NSMutableArray new];
for (HKObject *o in self.storedObjects) {
if ([sampleQuery.predicate evaluateWithObject:o]) {
[queryResults addObject:o];
}
}
SEL selector = NSSelectorFromString(#"resultHandler");
Method m = class_getInstanceMethod(HKSampleQuery.class, selector);
IMP imp = method_getImplementation(m);
typedef void(*resultHandler_t)(id, SEL, void(^)(HKQuery*, NSArray*, NSError*));
resultHandler_t f = (resultHandler_t)imp;
// here, I need to invoke the result handler block with sampleQuery, queryResults and nil as arguments
}
Note the selector name is "resultHandler" even though the parameter of the initializer of HKSampleQuery is called "resultsHandler".
Is there any way to invoke the block with appropriate arguments?
You're not doing what you think you are doing. You are getting the implementation of the method resultHandler (the getter method of the property resultHandler). The block you want is the value of the property resultHandler, which is the return value of running the getter method. In other words, you need to run the getter and get the result, not get the getter itself.
Simplest way to call the method and get the return value (since in this case the return value is a regular object pointer type) would be
typedef void (^resultHandler_t)(HKSampleQuery *query, NSArray *results, NSError *error);
resultHandler_t f = [sampleQuery performSelector:#selector(resultHandler)];
f(sampleQuery, queryResults, nil);
Alternately, if you declare (but not implement) the instance method or property resultHandler in a dummy category of HKSampleQuery, you can then access the property directly like resultHandler_t f = sampleQuery.resultHandler;

How to pass ivar into a function and set it without losing the reference to the original object

I am passing an ivar (NSMutableArray) into some method. I was expecting that if I modify the object inside the function, it would be reflected outside the function, but in this case I need to set the object; something like the following:
- (void) someMethod:(SMResponseObject *)response onData:(NSMutableArray *)imAnIvar {
imAnIvar = [response objects];
//Some other stuff
}
But I noticed that the memory reference of imAnIvar inside the function changes when I set it, and given that, the actual ivar doesn't change. I understand that the problem is that I'm changing the reference of the object inside the method, so it stops pointing to the ivar and then it points to some other random memory direction.
I thought about one solution to this problem, and it can be to ensure that the ivar is not nil before calling the function and do something like this:
- (void) someMethod:(SMResponseObject *)response onData:(NSMutableArray *)imAnIvar {
NSMutableArray *data = [response objects];
[arrayForTableView removeAllObjects];
for(id element in data){
[imAnIvar addObject:element];
}
//Some other stuff
}
So I use the original object instead of setting it directly. The problem is that in order for this to work I need to ensure that the ivar is not nil, which I think is not clean, because I'll need to do something like this on every call to the method:
if(!_ivar){
//alloc it
}
So my question is: Is there a way to force the local scope variable to point to the original variable even if I'm setting it? if not, is there any cleaner way to make this work?
Do you mean this?
- (void)setFoo:(SomeClass **)objPtr
{
*objPtr = someOtherObject;
}
// call it as:
SomeClass *foo = someObject;
NSLog(#"Before: %#", foo);
[self setFoo:&foo];
NSLog(#"After: %#", foo);
Why not use a getter for the array so that you need not check for the array being nil while using it?
-(NSMutableArray *)iAmAnIvar {
if(_iAmAnIvar == nil) {
_iAmAnIvar = [NSMutableArray array];
}
return _iAmAnIvar;
}
And when you have to set a value to the array, as you mentioned in your question, you could use
[self.iAmAnIvar removeAllObjects];
[self.iAmAnIvar addObject:someObj];
I believe you can use the - (id)copy; function of NSObject
so your code might look like this:
- (void)someFunction:(NSString *)someArg
{
NSString *str = [someArg copy];
}

Objective-C pass block as parameter

How can I pass a Block to a Function/Method?
I tried - (void)someFunc:(__Block)someBlock with no avail.
ie. What is the type for a Block?
The type of a block varies depending on its arguments and its return type. In the general case, block types are declared the same way function pointer types are, but replacing the * with a ^. One way to pass a block to a method is as follows:
- (void)iterateWidgets:(void (^)(id, int))iteratorBlock;
But as you can see, that's messy. You can instead use a typedef to make block types cleaner:
typedef void (^ IteratorBlock)(id, int);
And then pass that block to a method like so:
- (void)iterateWidgets:(IteratorBlock)iteratorBlock;
The easiest explanation for this question is follow these templates:
1. Block as a method parameter
Template
- (void)aMethodWithBlock:(returnType (^)(parameters))blockName {
// your code
}
Example
-(void) saveWithCompletionBlock: (void (^)(NSArray *elements, NSError *error))completionBlock{
// your code
}
Other use of cases:
2. Block as a Property
Template
#property (nonatomic, copy) returnType (^blockName)(parameters);
Example
#property (nonatomic,copy)void (^completionBlock)(NSArray *array, NSError *error);
3. Block as a method argument
Template
[anObject aMethodWithBlock: ^returnType (parameters) {
// your code
}];
Example
[self saveWithCompletionBlock:^(NSArray *array, NSError *error) {
// your code
}];
4. Block as a local variable
Template
returnType (^blockName)(parameters) = ^returnType(parameters) {
// your code
};
Example
void (^completionBlock) (NSArray *array, NSError *error) = ^void(NSArray *array, NSError *error){
// your code
};
5. Block as a typedef
Template
typedef returnType (^typeName)(parameters);
typeName blockName = ^(parameters) {
// your code
}
Example
typedef void(^completionBlock)(NSArray *array, NSError *error);
completionBlock didComplete = ^(NSArray *array, NSError *error){
// your code
};
This might be helpful:
- (void)someFunc:(void(^)(void))someBlock;
You can do like this, passing block as a block parameter:
//creating a block named "completion" that will take no arguments and will return void
void(^completion)() = ^() {
NSLog(#"bbb");
};
//creating a block namd "block" that will take a block as argument and will return void
void(^block)(void(^completion)()) = ^(void(^completion)()) {
NSLog(#"aaa");
completion();
};
//invoking block "block" with block "completion" as argument
block(completion);
One more way to pass block using с functions in example below.
I`ve created functions to perform anything in background and on main queue.
blocks.h file
void performInBackground(void(^block)(void));
void performOnMainQueue(void(^block)(void));
blocks.m file
#import "blocks.h"
void performInBackground(void(^block)(void)) {
if (nil == block) {
return;
}
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), block);
}
void performOnMainQueue(void(^block)(void)) {
if (nil == block) {
return;
}
dispatch_async(dispatch_get_main_queue(), block);
}
Than import blocks.h when necessary and invoke it:
- (void)loadInBackground {
performInBackground(^{
NSLog(#"Loading something in background");
//loading code
performOnMainQueue(^{
//completion hadler code on main queue
});
});
}
You also can set block as a simple property if it's applicable for you:
#property (nonatomic, copy) void (^didFinishEditingHandler)(float rating, NSString *reviewString);
make sure that block property is "copy"!
and of course you can also use typedef:
typedef void (^SimpleBlock)(id);
#property (nonatomic, copy) SimpleBlock someActionHandler;
Also you invoke or call a block in using usual c function syntax
-(void)iterateWidgets:(IteratorBlock)iteratorBlock{
iteratorBlock(someId, someInt);
}
More info on blocks here
http://developer.apple.com/library/ios/#documentation/cocoa/Conceptual/Blocks/Articles/bxGettingStarted.html#//apple_ref/doc/uid/TP40007502-CH7-SW1
I always tend to forget about blocks syntax. This always comes to my mind when I need to declare a block. I hope it helps someone :)
http://fuckingblocksyntax.com
I wrote a completionBlock for a class which will return the values of dice after they have been shaken:
Define typedef with returnType (.h above #interface declaration)
typedef void (^CompleteDiceRolling)(NSInteger diceValue);
Define a #property for the block (.h)
#property (copy, nonatomic) CompleteDiceRolling completeDiceRolling;
Define a method with finishBlock (.h)
- (void)getDiceValueAfterSpin:(void (^)(NSInteger diceValue))finishBlock;
Insert previous defined method in .m file and commit finishBlock to #property defined before
- (void)getDiceValueAfterSpin:(void (^)(NSInteger diceValue))finishBlock{
self.completeDiceRolling = finishBlock;
}
To trigger completionBlock pass predefined variableType to it
(Don't forget to check whether the completionBlock exists)
if( self.completeDiceRolling ){
self.completeDiceRolling(self.dieValue);
}
Despite the answers given on this thread, I really struggled to write a function which would take a Block as a function - and with a parameter. Eventually, here's the solution I came up with.
I wanted to write a generic function, loadJSONthread, which would take the URL of a JSON Web Service, load some JSON data from this URL on a background thread, then return an NSArray* of results back to the calling function.
Basically, I wanted to keep all the background-thread complexity hidden away in a generic reuseable function.
Here's how I would call this function:
NSString* WebServiceURL = #"http://www.inorthwind.com/Service1.svc/getAllCustomers";
[JSONHelper loadJSONthread:WebServiceURL onLoadedData:^(NSArray *results) {
// Finished loading the JSON data
NSLog(#"Loaded %lu rows.", (unsigned long)results.count);
// Iterate through our array of Company records, and create/update the records in our SQLite database
for (NSDictionary *oneCompany in results)
{
// Do something with this Company record (eg store it in our SQLite database)
}
} ];
...and this is the bit I struggled with: how to declare it, and how to get it to call the Block function once the data was loaded, and pass the Block an NSArray* of records loaded:
+(void)loadJSONthread:(NSString*)urlString onLoadedData:(void (^)(NSArray*))onLoadedData
{
__block NSArray* results = nil;
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
// Call an external function to load the JSON data
NSDictionary * dictionary = [JSONHelper loadJSONDataFromURL:urlString];
results = [dictionary objectForKey:#"Results"];
dispatch_async(dispatch_get_main_queue(), ^{
// This code gets run on the main thread when the JSON has loaded
onLoadedData(results);
});
});
}
This StackOverflow question concerns how to call functions, passing a Block as a parameter, so I've simplified the code above, and not included the loadJSONDataFromURL function.
But, if you are interested, you can find a copy of this JSON loading function on this blog:
http://mikesknowledgebase.azurewebsites.net/pages/Services/WebServices-Page6.htm
Hope this helps some other XCode developers !
(Don't forget to vote up this question and my answer, if it does !)
The full template looks like
- (void) main {
//Call
[self someMethodWithSuccessBlock:^{[self successMethod];}
withFailureBlock:^(NSError * error) {[self failureMethod:error];}];
}
//Definition
- (void) someMethodWithSuccessBlock:(void (^) (void))successBlock
withFailureBlock:(void (^) (NSError*))failureBlock {
//Execute a block
successBlock();
failureBlock([[NSError alloc]init]);
}
- (void) successMethod {
}
- (void) failureMethod:(NSError*) error {
}

memory leak when using callback

I'm having an issue with memory management when dealing with callbacks and async code in objective c.
I cant seem to find a way to release the instance that the callback is set on.
For example:
MyClass *myArchive = [[MyClass alloc] init] ;
[myArchive callBack:^(RKObjectLoader* objectLoader, id object ) {
NSLog(#"success");
} fail:^(RKObjectLoader* objectLoader, NSError* error) {
NSLog(#"failed");
}];
[myArchive searchArchive:words:paging];
The problem being that I don't know when or how to release the instance *myArchive. Using Instruments within xcode to profile my code I always get a leak here. The function searchArchive performs an async request to a server using restkit. I wont reference the instance from within the callback as I heard this causes a retain cycle and I have done some reading about using __block and other c approaches to avoid retain cycles which is all fine but as it stands now with no actual code happening within the callback how do I release the *myArchive instance. anyone able to explain how I should deal with this within objective-c?
EDIT:
This is where I set the callback in myclass
// Sets internal backs on this object which basically wrap the delegate
//
- (void)callBack: (void (^)(RKObjectLoader* objectLoader, id object))success
fail: (void (^)(RKObjectLoader* objectLoader, NSError* error))fail {
//sanity check
NSAssert(_currentDelegate != self, #"Delegate is another object. Can not set callback");
// store our callback blocks in the instance
_success = [success copy] ;
_fail = [fail copy] ;
}
and then release _success and _fail in dealloc
and within the #interface
#interface myClass : NSObject<RKObjectLoaderDelegate> {
// holds the block callback for "success"
void (^_success)(RKObjectLoader* objectLoader, id object);
// holds the block callback for "fail"
void (^_fail)(RKObjectLoader* objectLoader, NSError* error);
}
I hope this gives more insight into what I'm doing wrong.
EDIT 2:
Ok I'm beginning to see the errors now:
-(void)retrieveGallery{
//create call back for async and deal with the result
[_galleryItems callBack:^(RKObjectLoader* objectLoader, NSArray *objects) {
//success happy days. do a bunch of code here that does not cause leaks
} fail:^(RKObjectLoader* objectLoader, NSError* error) {
//retry the attempt to retrieve gallery data from the server
_retryCount++;
if (_retryCount < _maxRetryCount) {
[self retrieveGallery];
}
}];
//read the collection of gallery items from server
[_galleryItems readGallery];
}
The only actual memory leaks are when the callback catches a fail for what ever reason and then calls the [self retrieveGallery] function from within callback to attempt again. this is what is causing the leak so I'm guessing that is a big no no. How should I attempt the function (retrieveGallery in this case) again.
Memory management isn't really any different because you are using an asynchronous callback. myArchive should be a property of whatever class you are doing this in. You want it to stick around until the task is complete, right?
#property (retain) MyClass *myArchive;
Then..
myArchive = [[MyClass alloc] init];
void (^on_success_callback)(void) = ^(void){
NSLog(#"success");
self.myArchive = nil;
};
You need to make sure you are managing the callbacks properly, i.e. copying them from the stack and releasing them when you are done.
If you have retains and releases in your code you probably aren't using the accessor methods properly.

Objective-C Blocks - use as an object

With reference to the code below, once a block has been put into an array, how could you take that block object and run the actual code in the block.
Another Question: If I call a method in a block like below, does that block encapsulate the code in that method or capture the signature of the method and call it that way?
-(void)blockCalledMethod
{
NSLog(#"Hello World");
}
-(void)programStart
{
NSArray * array = [[NSArray alloc] initWithObjects:[[^ { [self blockCalledMethod];} copy] autorelease],nil];
id pointerToBlock = [array lastObject];
}
Call it like this:
void (^pointerToBlock)(void) = [array lastObject];
pointerToBlock(); // because ^ {} is void(^)(void)
You cannot declare pointerToBlock as an id if you want to call it directly, because the compiler has to recognize it as a block type and not just an object.
If I call a method in a block like above, does that block encapsulate the code in that method or capture the signature of the method and call it that way?
I should think self refers to the calling class.