Can blocks/methods be interchangeable? - ios

I'm coming from C#/Java/JS to objectiveC and I'm only a couple of days in, so go easy on me.
...so I have a method that takes a block as a parameter:
-(void)subToPub: (NSString*)publisherName
channelId: (NSString*)channelId
callback: (void(^)(NSDictionary*))cb
which I would usually use as follows:
[myObj subToPub:#"someId"
channelId:#"someOtherId"
callback:[(^(NSDictionary* msg){
NSLog(#"cb2: %#",msg);
}) copy]
];
Now, say I have another method with a compatible signature, for instance:
-(void)subscribeHandler:(NSDictionary*)msg{
NSLog(#"cb2: %#",msg);
}
is it possible to pass this in as the callback to the subToPub method above, or do I need to wrap this method call in a block?

Logically you need three pieces of information to make a call to the selector described. The object instance, the name of the selector and the dictionary parameter.
The block you pass accepts only one piece of information when called — the dictionary. Everything else needs to be captured within the block.
So, logically, the selector can't be a straight substitution for the block. Besides anything else, where does knowledge of which instance to call it on come from?
The only way to produce a record of 'this method on this specific object' and compact that into a single object is to put it into a block.
If you have a defined format of method you want to call (in this case, one with a single argument) and know the object implicitly then you might consider passing in a selector (SEL). So e.g.
[myObj subToPub:#"someId"
channelId:#"someOtherId"
callback:#selector(subscribeHandler:)
];
... and subsequently, assuming you know the object you want to talk to as obj and have stored the SEL you received as selector:
[obj performSelector:selector withObject:msg];
If you want to pass more than one argument then you need to start fooling about with NSInvocations; it's quite ugly and you'll soon start to appreciate why closures were added to the language.

you can do this
[myObj subToPub:#"someId"
channelId:#"someOtherId"
callback:[(^(NSDictionary* msg){
[object subscribeHandler:msg];
}) copy]
];

You need to wrap it. Clearly you know how to do that, e.g. ^(void)subscribeHandler:#[#"key": #"value"].

Related

How to return multiple results from Asynchronous method?

Note: This question doesn't have anything to do with the language used, i.e, Swift/ Objective-C
I can't seem to get my head around how such a problem can be solved.
How an asynchronous method which processes data continuously ,return back these processed values to a function?
Example Class structure of -> ClassName
A method named -(void)infoCallBack , this is the method you have to call to get returns continuously.
Inside -(void)infoCallBack -> an asynchronous method [self startRecording]is there, which does audio recording asynchronously using AudioQueues by using a callback method void AudioInputCallback(..param..).
Finally Inside void AudioInputCallback(..param..) -> a method -(void) processAudio is there, which continuously processes data and gives us an integer number.
How to call a method like [ClassName infoCallBack] in such a way that we keep getting all these processed integers continuously?
Edit : I have searched SO, and came across completion handler blocks : although completion handlers only return a value once after completionHandler() is called. Moreover, another problem in this method was how to pass around this completionHandler to multiple methods in the className Structure as shown.
I came across delegates, it said that when distinct values are being returned continuously and state of something changes, then we should call a delegate. But I was stuck at how I would return values after I call the function infoCallBack from ClassName, i.e, [ClassName infoCallBack] which continuously can feed the person calling this function with the values being processed.
Actually I don't completely understand your question but I will give you the answer in my understanding
In my opinion, you can use block to handle process update.
typedef void (^ProcessHandlerBlock) (NSInteger i);
- (void)infoCallBackWithProcessHandlerBlock:(ProcessHandlerBlock)block {
[self startRecordingWithProcessHandlerBlock:(ProcessHandlerBlock)block];
}
- (void)startRecordingWithProcessHandlerBlock:(ProcessHandlerBlock)block {
[self audioInputCallbackWithParam1:#"1" param2:#"2" processHandlerBlock:(ProcessHandlerBlock)block];
}
- (void)audioInputCallbackWithParam1:(id)param1 param2:(id)param2 processHandlerBlock:(ProcessHandlerBlock)block {
[self processAudioWithProcessHandlerBlock:(ProcessHandlerBlock)block];
}
- (void)processAudioWithProcessHandlerBlock:(ProcessHandlerBlock)block {
// Assume this is your process method callback
[NSTimer scheduledTimerWithTimeInterval:1.f repeats:YES block:^(NSTimer * _Nonnull timer) {
// After receive integer, pass it to block.
block(1);
}];
}
When you want to use them, call
[self infoCallBackWithProcessHandlerBlock:^(NSInteger i) {
NSLog(#"%l", i); // Do whatever you want here
}];
Inside the completion block of infoCallBackWithProcessHandlerBlock method, you can use result integer to do what you want.
I can't seem to get my head around how such a problem can be solved.
From the rest of what you've written I suspect you can get your head around this, you probably just need a rest. You've found the answer already without realising...
I have searched SO, and came across completion handler blocks : although completion handlers only return a value once after completionHandler() is called.
The phrase "completion handler block" might be written as "a block used as a completion handler" - a block is just a block, you can call it as many times as needed, store it in variables, etc. While a completion handler is typically only called once a, say, result reporter might be called multiple times.
Moreover, another problem in this method was how to pass around this completionHandler to multiple methods in the className Structure as shown.
A block is a kind of object and like other objects your class instance might need to use in many methods it doesn't need to be passed around but can be stored in an instance variable. For ease of use first declare your a shorthand for the block type, say:
typedef void (^SampleHandler)(int i);
then declare a suitable instance variable:
#implementation ClassName
{
SampleHandler mySampleHandler;
}
now use this like any other instance variable - initialise it (mySampleHandler = ...;), use it to call the block (mySampleHandler(42);`)
I came across delegates, it said that when distinct values are being returned continuously and state of something changes, then we should call a delegate. But I was stuck at how...
Blocks and delegates are often used for similar purposes, you can use either to solve your problem in essentially the same way - store the block/delegate reference in an instance variable, call the block/delegate method to return a value. You just have to decide which suits your use case best:
A block is a function. A block is created inline, usually at the call site, and can reference (and sometimes modify) variables in the environment where it is created. Like any function it is (usually) a single-operation thing - pass argument(s), produce a side-effect/return a result.
A delegate is an object. Like any other object it requires an interface/implementation. Like any object it can have multiple methods, so its a multi-operation thing.
In your case - returning a value - a block is probably the best option, but you need to decide.
HTH

Using makeObjectsPerformSelector with an object

I have an NSArray of objects and I want to perform the selector pinInBackgroundWithName:(NSString *) on each object. I know that I can use [arr makeObjectsPerformSelector:#selector(selector_name) withObject:obj]; but how does passing in the string to the withObject: argument work? For example, what if the selector I wanted to perform on the objects in the array had multiple arguments? Then would the withObject: argument we an NSArray of objects?
From the docs:
A selector that identifies the message to send to the objects in the array. The method must take a single argument of type id
So you can't use this for a selector with multiple arguments.
If you want to send a message with multiple arguments to each object in the array, you could roll your own version that takes an array, and then fills out an NSInvocation object that it then invokes on each object, or, if you wanted to be really fancy, use higher order messaging.
I would suggest ditching the selector-based calls and using enumerateObjectsUsingBlock or one of it's variants.
Blocks inherit their enclosing scope, so you can invoke a block of code that uses as many variables as you want from the scope of the call.

Difference between selector and SEL and method call [ ]? [duplicate]

What the difference between a method, a selector and a message in Objective-C?
This is a great question.
Selector - a Selector is the name of a method. You're very familiar with these selectors: alloc, init, release, dictionaryWithObjectsAndKeys:, setObject:forKey:, etc. Note that the colon is part of the selector; it's how we identify that this method requires parameters. Also (though it's extremely rare), you can have selectors like this: doFoo:::. This is a method that takes three parameters, and you'd invoke it like [someObject doFoo:arg1 :arg2 :arg3]. There's no requirement that there be letters before each part of the selector components. As I said, this is extremely rare, and you will not find it used in the Cocoa frameworks. You can work with selectors directly in Cocoa. They have the type SEL: SEL aSelector = #selector(doSomething:) or SEL aSelector = NSSelectorFromString(#"doSomething:");
Message - a message is a selector and the arguments you are sending with it. If I say [dictionary setObject:obj forKey:key], then the "message" is the selector setObject:forKey: plus the arguments obj and key. Messages can be encapsulated in an NSInvocation object for later invocation. Messages are sent to a receiver. (ie, the object that "receives" the message).
Method - a method is a combination of a selector and an implementation (and accompanying metadata). The "implementation" is the actual block of code; it's a function pointer (an IMP). An actual method can be retrieved internally using a Method struct (retrievable from the runtime).
Some other related things that you didn't ask for:
Method Signature - a method signature represents the data types returned by and accepted by a method. They can be represented at runtime via an NSMethodSignature and (in some cases) a raw char*.
Implementation - the actual executable code of a method. Its type at runtime is an IMP, and it's really just a function pointer. iOS 4.3 includes a new ability to turn a block into an IMP. This is really cool.
One of the fun things to realize is that the name of a method (the selector) is distinct from the implementation of the method (the IMP). This means that you can swap them around, if you're feeling daring. You can also add and remove methods at runtime, because all you're doing is editing an entry in a hash table: the key is the selector, and the value is the IMP of the method. This allows you to do some really crazy and trippy stuff. It's not for the faint of heart. :)
A method is the implementation which is run when an object or class is asked to perform some action. It is in the scope of its containing class and is therefore different when referenced through some other class. A selector is an identifier which represents the name of a method. It is not related to any specific class or method, and can be used to describe a method of any class, whether it is a class or instance method.
Simply, a selector is like a key in a dictionary. It can tell you what method someone is talking about, but only if you also have the dictionary itself (the class or object). The method is what you get when you ask for the value from the dictionary using the selector as a key.
This site has a good overview of all the terminology in question: http://www.otierney.net/objective-c.html
Check out the link, but I'll give a quick summary:
A method is essentially like a method of function that you are used to in your favourite programming language.
A message (from the article) "A message can be dynamically forwarded to another object. Calling a message on an object in Objective-C doesn't mean that the object implements that message, just that it knows how to respond to it somehow via directly implementing it or forwarding the message to an object that does know how to."
Selectors can mean two things. It can refer to the name of a method, or "refers to the unique identifier that replaces the name when the source code is compiled. Compiled selectors are of type SEL." (from: http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocSelectors.html)

function parameters not retained using Arc?

EDIT: This is for a static NSMutableDictionary, not a class member. I see a lot of answers thinking it's a class member, sorry about that. Thanks for the quick responses.
I had a working piece of code, but it was used 2x, so I wrote a convenience function:
- (void) initializeDictionary:(NSMutableDictionary*)mutableDict fromPathName:(NSString*)path
{
mutableDict = // get from file, init if not there.
}
Then I noticed nothing was saving. Stepping through the code, the function creates a dictionary, but the "passed in" value is still nil upon returning. This completely blows away my understanding of pointers (don't take this the wrong way, I'm very comfortable). But their purpose, I thought, was to let you "pass the address" so I could hydrate the thing it points to.
since mutableDict is the "value copy", ARC appears to be wiping it out. I'm asking here because
the other questions have the opposite question "Why is this being retained?" and
It doesn't seem right. Your very first tutorial in any pointer language is "so you can mess with the original value". Does Arc really do this? Is there a concept I'm not getting?
And of course, I may be overlooking something simple.
I seem to have solved it by doing the writeback trick I found elsewhere:
- (void) initializeDictionary:(NSMutableDictionary* __strong *)mutableDictionary fromPath:(NSString*)path;
and using the & to call and * deref to change the value. It just seems far less than elegant.
You pass a pointer of NSDictionary. If you change the pointer value of mutableDict (by allocation or assignment) this will NOT be reflected on the variable passed as this function's argument and since mutableDict is locally defined in the function it will be released by ARC automatically. (Do not forget that even for pointers the address is copied when passed to a function).
The reason that your second solution works is because you pass a pointer to a pointer (not sure if strong is needed there). The value of *mutableDict will be reflected outside since you update a value in the address pointed to by mutableDict. This value is the address of your allocated dictionary and since you change it via a pointer it will be reflected outside the function.
To do what you want you use multiple indirection
- (void) initializeDictionary:(NSMutableDictionary**)mutableDict fromPathName:(NSString*)path
{
mutableDict = // get from file, init if not there.
}
Notice the parameter is (NSMutableDictionary **), a pointer to a pointer to an NSMutableDictionary.
To call the method you need to create a pointer and pass it in like this:
NSMutableDictionary *mutableDictionary;
[self initializeDictionary: &mutableDictionary fromPathName:...];
And on return, the mutableDictionary variable will have been initialised by the method.
However, It's probably easier to just return the dictionary from the method rather than doing it this way.
In Objective-C if you define a variable in a method, the variable is visible only in that method.
If you need to save the variable to use it outside, you need to "return" it from your function. What you did wasn't a trick, is another way of returning a variable.
Try with:
- (void)initializeDictionaryFromPath:(NSString*)path {
NSMutableDictionary *mutableDict = // your initialization
return mutableDict;
}
Then you can define your dictionary with this code:
NSMutableDictionary *mutableDict = [self initializeDictionaryFromPath:path];

What is the use of storing the block in an instance variable

I am aware that blocks are one of the latest feature added in ios. But I am really finding a
tough time learning it .
I have seen people doing the following
typedef void(^CallBackBlk) (NSString *);
#property(copy,nonatomic)CallBackBlk block;
and in .m class
-(void)doSomething:(CallBackBlk )cb{
self.block=cb;
}
I never understood what is the use of assigning it to cb here. Can't I simply do the following
-(void)doSomthing{
block(#"my string");
}
I am really not getting the purpose of storing the block in instance variable. Can any help
me with an example. Any help is greatly appreciated
In your doSomething method, where does block come from?
Answer that, and you'll have your reason.
Ah -- the commentary makes the question clear. Snark served a purpose (snark and too lazy to type out a real answer on my iPhone at 7AM :).
An instance variable is just a slot to put things. Nothing is in that slot to start with.
In your case, you could implement:
-(void)doSomething:(CallBackBlk )cb{
cb();
}
However, typically, a callback is used when you do something asynchronously. For example, you might do:
[myObject doSomething:^{
NSLog(#"did something");
}];
And then:
-(void)doSomething:(CallBackBlk)cb {
dispatch_async(... global concurrent queue ..., ^{
... do some work ...
cb();
});
}
That is, doSomething: will return as soon as the dispatch_async() happens. The callback block is used to callback to let you know that asynchronous operation is done.
Of course, still no need for an instance variable. Take that class that does something a bit further; make it some kind of relatively complex, state transitioning, engine. Say, like your average internet downloader or compute heavy simulation engine. At that point, lumping all your background work into a single method would be overly complex and, thus, shoving the callback block(s) (there may likely be more than one; a progress updater, a completion block and/or an error block, for example) into instance variables allow the class's implementation to be subdivided along lines of functionality more cleanly.
What is the use of storing the block in an instance variable
Perhaps to be able to access it later?
You would do that if you want to invoke the block later, after the method that assigns it has already returned.
Consider for example an object that manages a download. You might want to have a block that gets invoked when the download completes (e.g. to update the UI), but you don't want the download method to have to wait until that happens (because it might take a long time).
maybe and example of use will help..
one use for storing it as a variable i have found is if you have multiple views that all access another view (for me it was a map on the next view) i used blocks that were setup by the previous view (set the default location for the map, initialise markers and so forth) then passed it through to the next view, where it would run it, setting up the map. it was handy having the block use the local variables of the previous view to access certain attributes. it wasnt the only way to do it, but i found it was a nice clean way of going about it.
and here is an example of what gets run in the viewDidLoad of the mapview
if(setupMap){
setupMap(mapView);
}
if(gpsUpdate){
gpsUpdate(mapView);
}
if(addMarker){
addMarker(mapView);
}
now if those blocks were assigned (the if statement check if they are nil), it would run them and do the appropriate setup for the map. not every view needed to do those, so they would only pass to the map view what needed to be done. this keeps the map view very general purpose, and code gets reused a lot. write once use lots!
To use the block, you call your doSomething: method:
CallBackBlk laterBlock = ^(NSString *someString) {
NSLog(#"This code is called by SomeClass at some future time with the string %#", someString);
};
SomeClass *instance = [[SomeClass alloc] init];
[instance doSomething:laterBlock];
As you code the implementation of your class, it will presumably reach some condition or finish an action, and then call the laterBlock:
if (someCondition == YES) {
self.block("Condition is true");
}

Resources