I have a method called LoginAttempt: with the following class header:
- (IBAction)LoginAttempt:(UIButton *)sender
and I'm trying to call this method in the same class' textFieldShouldReturn: method like this:
[self LoginAttempt:(SENDER TYPE HERE)];
The problem is, I can't figure out what to call where I put 'SENDER TYPE HERE', running Xcode 5, iOS 7.1 I believe, and Xcode has a suggestion: (UIButton *), like I'm supposed to enter a UIButton as the sender. Sorry if this is really amateur, but I'm really new to Objective-C and C, so I'm not really sure what it wants.
I have tried self.self, changing the cast on sender in LoginAttempt to id, and just taking away the (UIButton *).
How do I successfully call LoginAttempt:?
You can always just pass nil.
[self LoginAttempt:nil];
As the method is an IBAction, it's designed to be hooked up to a IB element and the sender argument will be a reference to the UI element that called the method. You can send anything or nothing though. Most likely, your implementation of the method doesn't even use the sender variable, so sending nil is more than fine.
And by the way, method names should begin with lowercase letters...
Related
when I'm trying to call a method on an object of type id, i get a warning raised (method not found). how i call the method :
Class A *instanceACasted = (ClassA *)idvalue ;
then call the method
[instanceACasted methodCall];
This is one way but i dont know about the class name using id how i call the method
You can use introspection and performSelector:
SEL selector = #selector(yourMethodSignature:);
if ([obj respondsToSelector:selector]) {
[obj performSelector:selector];
}
Apple documentation on how to use introspection.
To get rid of the warning method not found , you must cast/convert your id type object to the proper object type. But in this case you need to know the Class name of id type object.
If you don't know the class name then follow this answer.
The correct answer depends heavily on what you are actually doing. Your code doesn't compile, and your error message "method not found" does not exist in Clang, so I can't tell what is actually happening. Also, your subject contradicts what I might guess from your code (there is no mention of "id" in your code). Here are a few guesses:
You are calling a method that has not been declared
ObjC mostly reads code from top to bottom, and reads each source file (implementation file, .m file, not header) separately, as its own "compilation unit". So if your source file tries to call a method that is not in your file, you'll get an error message like error: no known instance method for selector 'doSomething' or error: no known class method for selector 'doSomething'.
To fix that, you need to #import the header that declares the class/protocol that defines the method you want to call.
You are calling a class method on an instance (object) or an instance method on a class
Class methods start with a +, instance methods with a -. They are totally separate. So if you declare a method with a +, then call it on an object of that type (instead of on myObject.class or the class name), the compiler may warn you about error: no known instance method for selector 'doSomething' resp. error: no known class method for selector 'doSomething'. Here the important part is that it is looking for a class method, even though an instance method exists, and vice versa.
You are calling a method that the given object/class does not have
In that case, you get an exception that bounces you back into the run loop and a log message at runtime. This could mean that your code is expecting a newer OS's version of a class (which has that method) but is running on an older OS (where this method didn't exist yet). In that case, you get a message like unrecognized selector sent to instance 0x7fffdb13cf38 or unrecognized selector sent to class 0x7fffdb13cf38.
To fix that, you can check whether an object responds to a given method by asking it [theObject respondsToSelector: #selector(doSomething)], and only then calling it, otherwise doing something equivalent that doesn't rely on that method. Or you could check if that method is available ahead of time and just hide the button or whatever that needs this on older OSes that way.
Note that, if you had e.g. an NSObject* and you knew that in one special case it could actually be an NSString*, and you use -respondsToSelector: to verify that it implements #selector(characterAtIndex:) in that case, you may still get an error message that NSObject instances do not responds to -characterAtIndex:. In this case, you can turn off that warning by doing:
NSObject* myNSObject = myArray.firstObject;
if( [myNSObject respondsToSelector: #selector(characterAtIndex:)] )
[(NSString*)myNSObject characterAtIndex: 0];
or whatever. You usually never write code like this, though. Checking "what class is my object" is usually an indicator that you built your class hierarchy wrongly, so I only mention that for completeness' sake.
How does 'id' figure into this?
You mention id in your headline, but your example doesn't use it. If you call a method on id, ObjC will let you do anything. All it wants is that somewhere there is a class or instance method declaration for the given method, on any object. In that case, it will only blow up at runtime if you call a method the given object doesn't have.
Whenever I create an IBAction I always have to set the default Type (sender) from AnyObject to the only other option which is the actual class type.
Is there a reason for it to always default to AnyObject rather than the object I have explicitly added?
I believe I understand the difference between a UIObject and AnyObject but I fail to see why AnyObject should be the default.
One reason I can think of is let's say I write the interface of an object first but I don't know yet what control type will invoke the action. Or further more I end up with more than one type of control.
By defaulting to AnyObject it fits nicely with objc id type. Also it is scaleable and will work for the general case.
It's also part of Target-Action whereby only certain method signatures must be implemented for it to work.
This extract gives a good scenario -
The senderparameter usually identifies the control sending the action message (although it can be another object substituted by the actual sender). The idea behind this is similar to a return address on a postcard. The target can query the sender for more information if it needs to. If the actual sending object substitutes another object as sender, you should treat that object in the same way. For example, say you have a text field and when the user enters text, the action method nameEntered: is invoked in the target:
- (void)nameEntered:(id) sender {
NSString *name = [sender stringValue];
if (![name isEqualToString:#""]) {
NSMutableArray *names = [self nameList];
[names addObject:name];
[sender setStringValue:#""];
}
}
Here the responding method extracts the contents of the text field, adds the string to an array cached as an instance variable, and clears the field. Other possible queries to the sender would be asking an NSMatrix object for its selected row ([sender selectedRow]), asking an NSButton object for its state ([sender state]), and asking any cell associated with a control for its tag ([[sender cell] tag]), a tag being a numeric identifier
It makes sense to default to id / AnyObject as you can always change it to ensure better type safety.
Actually, you can set an IBAction to any class in the hierarchy of that object. If you for example have a class named YellowButton that is a subclass of UIButton, you'll be able to choose between AnyObject, UIButton and YellowButton.
Another thing to consider is that you can have many objects attached to the same IBAction. And they don't even need to be of the same type. For instance, you can have a UIBarButtonItem and a UIButton connected to the same IBAction. You can only do that if the sender type is set to AnyObject.
Now, why Apple chose AnyObject to be the default I can only guess. I think it would be because you can type cast the sender in your method without loosing any information. That way you can even take different actions based on the sender's class.
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)
In an if/else function depending on the conditions that're met I want to show some string as result to the user. I'm trying to do this by changing to a new viewController programatically. I have created a method 'showresult' that will be taking one variable 'result' as argument and then changing viewController and showing the content of 'result' on there.
For changing the viewController I now have:
Defined in .h as:
Then I'm trying to call this getData method in an if/else function:
Here I get 'no visible #interface for 'NSString' declares the selector 'getData'
I assume the error lies in my definition of the method, I just can't see why
--UPDATED Part--
I have now reached a point where the following way of changin viewController works for me:
[self performSegueWithIdentifier:#"gotoresult" sender:self];
Now I just need the last part, which is to pass on a variable to the new viewController. I have found other threads about passing something on, but just didn't understand how to apply this.
One suggestion I found was this one, but prepareforSegue isn't recognized in my Xcode
-(void)prepareforSegue:(UIStoryboardSegue *)segue sender:(id)sender{
GTImageView * viewController = segue.destinationViewController;
viewController.someData = 99;
}
I just need to be able to show some string on to that new viewController
The compiler is not complaining about self because the identifier is unknown but because the way you declare your method is wrong. In Objective-C you define methods like this:
- (returnType)doSomethingWithTheFirstParameter:(param1Type)param1 secondParameter:(param2Type)param2 {
// body
}
The name of your method would be -doSomethingWithFirstParameter:secondParamter:.
In the same manner you can add as many parameters as you like. So in your case the correct method definition would be:
- (NSString *)showResult:(NSString *)result {
// body
}
As this is very basic stuff I suggest you first read an introduction to Objective-C or do a tutorial in order to get familiar with the syntax, e.g. Programming with Objective-C.
Question has been edited. Answer to your new question:
The compiler tells you what's wrong with that code: In your if-branch you call the message getData on the object result which seems to be of class NSString. But you added the getData method to your view controller class. So when you want to call that method from inside the view controller you need to use
[self getData:result];
instead.
Furthermore you should not return 0 for a method of return type NSString. If you do not want the method to return anything change the method definition to:
- (void)showResult:(NSString *)result {
// body
}
and remove the line
return 0;
or return some NSString object.
Note: Please do not include screenshots of your code but copy the code and paste the text to your post instead. Besides other advantages you give other users the option to copy your code and try it out.
I'm trying to close a superview by using this method [self.superview buttonPressedClose];
I have already implemented that method in my superview, and everything works.
But it gives me an alert "UIView may not respond to 'buttonPressedClose'" during compile.
If I change it to the following line, it doesn't give me the alert, but is this the correct way to do it?
if ([self.superview respondsToSelector:#selector(buttonPressedClose)]) {
[self.superview performSelector:#selector(buttonPressedClose) withObject:nil afterDelay:0.0];
}
Thanks.
**Edited typo..
Is this a typo in question or in your code?
if ([self.superview respondsToSelector:#selector(buttonPressedClose)]) {
// vv here
[self.superview performSelector:#selector(buttonPressedCLose) withObject:nil afterDelay:0.0];
}
In general, self.superview returns an object of type UIView, and your buttonPressedClose is a custom selector that's not implemented in UIView. That's why you're getting a warning.
You might want to cast self.superview to your desired type, e.g.:
[(MyView *)self.superview buttonPressedClose];
or make it even more mysterious and cast to id - compiler doesn't check for selectors presence then:
[(id)self.superview buttonPressedClose];
That said, all of the above solutions are a bit smelly.
One very important thing regarding performSelector: with zero delay - it doesn't execute the selector in place, but rather it posts selector execution to thread's run loop and executes it when control returns to the run loop (i.e. when call stack is empty). So in normal situations you wouldn't like to use it.
"is this the correct way to do it?"
No, there is no reason to do it this way. afterDelay:0 is only used if you want to not execute it immediately. If you want to execute it immediately, then you should use performSelector: without afterDelay:.
But using performSelector: directly like this has no benefit. It is equivalent to, and is a more convoluted way of, calling the method directly. The warning you are getting is purely a static type-checking issue. The type (UIView *) is not guaranteed to have that method. You need to cast it to the expected view type that supports the method, or cast it to id to turn off checking of methods. When you used performSelector:, that also skirts around static type checking of methods, so it is strictly no better than casting it to id and then calling it.