Is there something about this method name that indicates it's asynchronous? - objective-c

I've inferred what a lot of things DO in Objective-C, and I've gone through several tutorials that simply talk about the data types, but I haven't run across anything that simply explains the syntax.
For starters, what does this mean? What it does is start a thread and get data returned from a server:
- (void)apiCall:(void (^)(NSMutableArray *list))block {
Does something in that function header tell me that it is asynchronous? is that what block means?

No, block doesn't mean asynchronous, a block in Obj-C is just a bit of code that can be passed as an argument to a method.
methods that start with - are instance methods and those that start with + are class methods.
^ is a syntactic marker to denote a block.

For your first question: you would have to look at the API documentation to find out if it is asynchronous.
For more information about blocks in general, see here:
Apple Blocks Programming Guide

Let's start with your second bullet:
Class methods are declared with +, instance methods are declared with -.
The first and third are related, the parameter named block is a code block, it's a piece of code intended to be run later. Given the name of this method apiCall, I suggest this being the method run after the call is done.
It would we natural to suspect that this method will do some work on another thread and then invoke the block you supplied, but for this you'd need to check the documentation or the code.
The signature: (void (^)(NSMutableArray* list)) block describes a code block with a void return type and a NSMutableArray* list as only parameter.
An example usage of the block parameter would be:
void (^apiCallCallback)(NSMutableArray*) = ^(NSMutableArray* list) {
NSLog(#"The API returned %d items in a list", [list length]);
}
[someApiInstance apiCall:apiCallCallback];
After the API instance is done doing whatever it is suppose to do, you'll see that the log statement is printed.

Related

Objective-C's "obj performSelector" vs objc_msgSend( )?

Going through Apache Cordova's source code, I ran into two lines of code that I'm puzzled about:
//[obj performSelector:normalSelector withObject:command];
objc_msgSend(obj,normalSelector,command);
From Apple's documentation, there doesn't seem to be a lot of difference between these two methods.
id objc_msgSend(id theReceiver, SEL theSelector, ...)
Sends a message with a simple return value to an instance of a class.
- (id)performSelector:(SEL)aSelectorwithObject:(id)anObject
Sends a message to the receiver with an object as the argument. (required)
What exactly is the difference between these two methods? In the case above, both are sending messages with an object as an argument to a receiving object.
You're asking the difference between two "methods" but only one of them is actually a method. The objc_msgSend function is, well, a function. Not a method.
The objc_msgSend function is the function that you actually call when you invoke any method on any object in Objective C. For example, the following two are basically equivalent:
// This is what the compiler generates
objc_msgSend(obj, #selector(sel:), param);
// This is what you write
[obj sel:param];
// You can check the assembly output, they are *almost* identical!
The major difference here is that objc_msgSend does not get type checked by the compiler -- or at least, its arguments don't get type checked against the selector's parameter types. So the following are roughly equivalent:
[obj performSelector:normalSelector withObject:command];
objc_msgSend(obj, #selector(performSelector:withObject:),
normalSelector, command);
But, that's a bit of a waste, since all performSelector:withObject: does is call objc_msgSend.
HOWEVER: You should stay away from obc_msgSend because it is not type-safe, as mentioned above. All the apache devs are doing is removing a single method call, which will only give you very slight performance benefits in most cases.
The commented out line is correct, the objc_msgSend() line is incorrect in that it needs to be explicitly typed (varargs are not compatible with non-varargs function calls on some platforms sometimes).
Effectively they do the same thing. Really, the method call version is just a wrapper around objc_msgSend().

Objective-C Selector pointer to be passed to a C function

I have a C struct that contains a function pointer. Now, I have used this setup within C with no problems, but now I'm using this C struct in Objective-C and I need to pass a function (or selector) pointer that is defined in the Objective-C class.
1. Here is what I have for the Objective-C selector that needs to be passed as a pointer to the C function:
- (void)myObjCSelector:(int*)myIntArray
{
// Do whatever I need with myIntArray
}
2. And here is where I run into a wall, Within Objective-C I'm trying to pass the selector as a pointer to the C function call: In place of "myObjCSelectorPointer" I need the proper syntax to pass the selector as a function pointer in this C function call:
passObjCSelectorPointerToCContext(cContextReference, myObjCSelectorPointer);
I did investigate this issue, but could mainly find several different ways of doing similar things, but I couldn't find anything specific for calling C functions and passing an Objective-C selector pointer.
In objc a selector is not a function pointer. A selector is a unique integer that is mapped to a string in a method lookup table stored by the objc runtime. In the above case your method name would be myObjCSelector: and to get the unique selector for it you would type #selector(myObjCSelector:). However this would be of no use to you because it doesnt represent a particular implementation of a function.
What youre looking for is IMP. Refer to this SO question.
EDIT 2:
IMP myObjCSelectorPointer = (void (*)(id,SEL,int*))[self methodForSelector:#selector(myObjCSelector:)];
Then you can call the method using
myObjCSelectorPointer(self,#selector(myObjCSelector:),myIntArray);
However, what this means you will need to make sure that you add the pointer to self in the c function call passObjCSelectorPointerToCContext.
So it should look like this
passObjCSelectorPointerToCContext(cContextReference, self, myObjCSelectorPointer);
when called from within the object that contains the method.
It is important to note though that using IMP is almost never the right technique. You should try to stick with pure Obj-C. Obj-C is quite efficient after the first call to a message because it uses temporal caching.
EDIT 1:
It's useful to understand why objc works in this way. The Apple documents explain it in depth. However a short explanation is as follows:
When you send a message to an object such as [myobject somemethod] the compiler won't immediately know which particular implementation of somemethod to call because there might be multiple classes with multiple overriden versions of somemethod. All of those methods have the same selector, irrespective of its arguments and return values and hence the decision about which implementation of somemethod is deffered to when the program is running. [myobject somemethod] gets converted by the compiler into a C function call:
objc_msgSend(myobject, #selector(somemethod))
This is a special function that searches each myobject class layout to see whether that class knows how to respond to a somemethod message. If not it then searches that class's parent and so on until the root. If none of the classes can respond to somemethod then NSObject defines a private method called forward where all unknown messages are sent.
Assuming that a class can respond to the somemethod message then it will also have a particular pointer of type IMP that points to the actual implementation of the method. At that point the method will be called.
There is considerably more to this procedure than I have described but the outline should be enough to help you understand what the goal of a selector is.
One final point is that the reason method names are mapped to unique integers via the #selector directive is so that the runtime doesn't have to waste time doing string comparisons.
Basically, the answer is: Objective-C selectors are different from function pointers. You need two pieces of data to perform a selector. That is an object and the selector itself. You will need some glue to accomplish your task.
Check this question.
Do you have to use a function pointer? In Objective-C, you can get the function pointer to an arbitrary method implementation (known as an IMP), but this is extremely uncommon, and usually not a good idea. Calling objc_msgSend() directly is also not the greatest idea, because there are several different variants of objc_msgSend(), and the compiler automatically chooses different ones to use based on the return type of the method. Methods that return an object go through objc_msgSend(), but objects that return structs might go through objc_msgSend() or they might go through objc_msgSend_stret(). And if the method returns a double, then it goes through objc_msgSend_fpret()...
Documentation: Objective-C Runtime Reference: Sending Messages
Instead, I might recommend using a target-action pair, or using a block. Then you might do something like:
myContextRef->target = anObjcObject;
myContextRef->action = #selector(invokeMe:);
And when you're done, do:
[myContextRef->target performSelector:myContextRef->action withObject:someReturnInformation];
Or maybe use a block:
myContextRef->completionHandler = [^(id returnInformation) {
[anObjcObject invokeMe:returnInformation];
} copy];
And then when you're done, do:
myContextRef->completionHandler(someReturnInformation);
(and don't forget to -release the block when you free the context)

Arguments by reference in Objective-C

I'm trying to pass an NSString by reference but it doesn't work.
This is the function:
+(void)fileName:(NSString *) file
{
file = #"folder_b";
}
and this is the call:
NSString *file;
[function fileName:file];
nslog(#"%#",file); // and there is nothing in the string....
What I must do to pass my string by reference?
If you want to return a value, then return a value. Pass by reference in Cocoa/iOS is largely limited to NSError**.
Given:
+(void)fileName:(NSString *) file
Then do:
+(NSString *) fileName;
And be done with it.
If you need to return more than one value at a time, that begs for a structure or, more often, a class.
In Objective-C, pass by reference smells like you are doing it wrong.
Pass by reference in Objective-C is reserved largely for returning NSError* information about a recoverable failure, where the return value of the method itself indicates whether or not the requested task succeeded or failed (you can pass NULL as the NSError** argument to allow the method to optimize away creating said error metadata).
Pass by references is also used to retrieve interior state of objects where the return value is effectively a multi-value. I.e. methods from AppKit like the following. In these cases, the pass-by-reference arguments are typically either optional or are acting as secondary return values.
They are used quite sparingly across the API. There is certainly use for pass by reference, but -- as said above -- doing so should be quite rare and rarer still in application code. In many cases -- and in some of the cases below, potentially -- a better pattern would be to create a class that can encapsulate the state and then return an instance of said class instead of pass by reference.
NSWorkspace.h:- (BOOL)getInfoForFile:(NSString *)fullPath application:(NSString **)appName type:(NSString **)type;
NSTextView.h:- (void)smartInsertForString:(NSString *)pasteString replacingRange:(NSRange)charRangeToReplace beforeString:(NSString **)beforeString afterString:(NSString **)afterString;
NSAttributedString.h:- (BOOL)readFromURL:(NSURL *)url options:(NSDictionary *)options documentAttributes:(NSDictionary **)dict;
NSNib.h:- (BOOL)instantiateWithOwner:(id)owner topLevelObjects:(NSArray **)topLevelObjects NS_AVAILABLE_MAC(10_8);
NSSpellChecker.h:- (NSRange)checkGrammarOfString:(NSString *)stringToCheck startingAt:(NSInteger)startingOffset language:(NSString *)language wrap:(BOOL)wrapFlag inSpellDocumentWithTag:(NSInteger)tag details:(NSArray **)details NS_AVAILABLE_MAC(10_5);
I believe you're looking for:
+ (void)fileName:(NSString **)file
{
*file = #"folder_b";
}
What's really done here is we're working with a pointer to a pointer to an object. Check C (yup, just plain C) guides for "pointer dereference" for further info.
(...But as has been pointed out repeatedly, in this particular example, there's no reason to pass by reference at all: just return a value.)
Passing a pointer to your object is the Objective C (and C) way of passing by reference.
I agree with 'bbum' that a perceived need to pass by reference is a signal to think about what you are doing; however, it is by no means the case that there are not legitimate reasons to pass by reference.
You should not create classes willy-nilly every time you have a function or method that needs to return more than one value. Consider why you are returning more than one value and if it makes sense to create a class for that then do so. Otherwise, just pass in pointers.
-Just my 2 cents
Try this
+(void)filename:(NSString **)file {
*file=#"folder_b";
}
and send the file as &file like:
NSString *file;
[function fileName:&file];
nslog(#"%#",file);
hope this will work.
I suspect this is because NSString is immutable. Have you tried NSMutableString?

How to call a method with parameters using #selector

I have two methods with same name but different parameters say:
-(void)methodA:(NSString*)string
-(void)methodA:(NSNotification*)notification
Now i need to call those methods using #selector with the parameters. How to do it ?
SEL aSel = #selector(methodA:);
[objectTakesString performSelector:aSel withObject:#"A string!"];
[objectTakesNtfctn performSelector:aSel withObject:[NSNotification notificationWith...]];
-[NSObject performSelector:withObject:] takes both the selector to be invoked, and a pointer to the parameter to pass it.
In my opinion, both the preceding answers are wrong. If you use
-[NSObject performSelector:withObject:];
as Sixten Otto suggests, you would have to place this at the beginning of your method:
-(void)methodA:(id)stringOrNotification
{
if ([stringOrNotification isKindOfClass:[NSString class])
{
..do something..
}
if ([stringOrNotification isKindOfClass:[NSNotification class])
{
..do something else..
}
. . .
}
Apart from this (bad) approach, what you're asking for can't in fact (easily) be done in Objective-C, because the language doesn't support parametric polymorphism. In other words, the type information is not used in the message dispatch. Yet another way to say this is that there can't be "two methods with same name but different parameters" in the same class. In fact, I'm surprised that you haven't yet seen a compiler error if you tried to declare this.
(If you've got the two methods defined on different classes, as dreamlax seems to assume, the message invocation will work trivially, even if you don't use performSelector:. Like so:
id eitherStringOrNotification;
[objectOfUncertainClass methodA:eitherStringOrNotification];
If that's what you're asking for, you don't have a problem.
)
Note that the NSMethodSignature object does contain information about the parameter types, but it's generated by the receiving object, so you can't really use it to distinguish between messages based on what parameter types are handed in (since that information is not available when the method signature is instantiated).

Selectors in Objective-C?

First, I'm not sure I really understand what a selector is. From my understanding, it's the name of a method, and you can assign it to a class of type 'SEL' and then run methods such as respondToSelector to see if the receiver implements that method. Can someone offer up a better explanation?
Secondly, to this point, I have the following code:
NSString *thing = #"Hello, this is Craig";
SEL sel = #selector(lowercaseString:);
NSString *lower = (([thing respondsToSelector:sel]) ? #"YES" : #"NO");
NSLog (#"Responds to lowercaseString: %#", lower);
if ([thing respondsToSelector:sel]) //(lower == #"YES")
NSLog(#"lowercaseString is: %#", [thing lowercaseString]);
However, even though thing is clearly a kind of NSString, and should respond to lowercaseString, I cannot get the 'respondsToSelector' conditional to return "YES"...
You have to be very careful about the method names. In this case, the method name is just "lowercaseString", not "lowercaseString:" (note the absence of the colon). That's why you're getting NO returned, because NSString objects respond to the lowercaseString message but not the lowercaseString: message.
How do you know when to add a colon? You add a colon to the message name if you would add a colon when calling it, which happens if it takes one argument. If it takes zero arguments (as is the case with lowercaseString), then there is no colon. If it takes more than one argument, you have to add the extra argument names along with their colons, as in compare:options:range:locale:.
You can also look at the documentation and note the presence or absence of a trailing colon.
Selectors are an efficient way to reference methods directly in compiled code - the compiler is what actually assigns the value to a SEL.
Other have already covered the second part of your q, the ':' at the end matches a different signature than what you're looking for (in this case that signature doesn't exist).
That's because you want #selector(lowercaseString), not #selector(lowercaseString:). There's a subtle difference: the second one implies a parameter (note the colon at the end), but - [NSString lowercaseString] does not take a parameter.
In this case, the name of the selector is wrong. The colon here is part of the method signature; it means that the method takes one argument. I believe that you want
SEL sel = #selector(lowercaseString);
NSString's method is lowercaseString (0 arguments), not lowercaseString: (1 argument).
Don't think of the colon as part of the function name, think of it as a separator, if you don't have anything to separate (no value to go with the function) then you don't need it.
I'm not sure why but all this OO stuff seems to be foreign to Apple developers. I would strongly suggest grabbing Visual Studio Express and playing around with that too. Not because one is better than the other, just it's a good way to look at the design issues and ways of thinking.
Like
introspection = reflection
+ before functions/properties = static
- = instance level
It's always good to look at a problem in different ways and programming is the ultimate puzzle.
From my understanding of the Apple documentation, a selector represents the name of the method that you want to call. The nice thing about selectors is you can use them in cases where the exact method to be called varies. As a simple example, you can do something like:
SEL selec;
if (a == b) {
selec = #selector(method1)
}
else
{
selec = #selector(method2)
};
[self performSelector:selec];
As per apple docs:
https://developer.apple.com/library/archive/documentation/General/Conceptual/DevPedia-CocoaCore/Selector.html
A selector is the name used to select a method to execute for an object, or the unique identifier that replaces the name when the source code is compiled. A selector by itself doesn’t do anything. It simply identifies a method. The only thing that makes the selector method name different from a plain string is that the compiler makes sure that selectors are unique. What makes a selector useful is that (in conjunction with the runtime) it acts like a dynamic function pointer that, for a given name, automatically points to the implementation of a method appropriate for whichever class it’s used with. Suppose you had a selector for the method run, and classes Dog, Athlete, and ComputerSimulation (each of which implemented a method run). The selector could be used with an instance of each of the classes to invoke its run method—even though the implementation might be different for each.
Example:
(lldb) breakpoint --set selector viewDidLoad
This will set a breakpoint on all viewDidLoad implementations in your app.
So selector is kind of a global identifier for a method.