I created a static library for use in my other iOS application projects. The way it works is the application project implements the protocol in my static library and calls a method in the static library. Then the static library presents a view on top of the calling view. Here's how the code is:
MyFile.h file of the main class in delegate:
#protocol MyHandlerDelegate <NSObject>
- (void)infoRetrieved:(BOOL)success;
#end
#interface MyFile : UIViewController
{
id <MyHandlerDelegate> delegate;
}
#property (retain) id delegate;
MyFile.m contains:
- (void)showRewards
{
[[[self delegate] view] addSubview:view1];
}
Now when I created a dummy application with just a single button, this worked fine and the static library successfully presented a view on top of the calling view.
Now I need to make this work in an open source game TweetJump (built on Cocos2D). In the highscores class, I have included the header file and implemented the delegate. In the implementation file, I call the following code:
MyFile *mf = [[MyFile alloc] init];
[mf setDelegate:self];
[mf showRewards];
For your consideration, I have hosted the Highscore class - Header and Implementation. The error that I am getting when the above method is executed is:
2013-04-16 23:54:42.658 tweejump[11502:c07] +[Highscore view]: unrecognized selector sent to class 0xecc08
2013-04-16 23:54:42.661 tweejump[11502:c07] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+[Highscore view]: unrecognized selector sent to class 0xecc08'
I know its a tedious question. Will greatly appreciate the help. Thanks
It's telling you that Highscore class does not have a view method. You protocol says the delegate only has to be an NSObject nothing more specific.
It looks like you're calling this code in a class method rather than an instance method. An object is not interchangeable with its class. Have your actual Highscore object do this instead of the class.
Related
I need to add method to NSURLSessionTask. Here's my category which is supposed to do that:
// NSURLSessionTask+Extras.h
#import <Foundation/Foundation.h>
#interface NSURLSessionTask (Extras)
- (void)helloNSURLSessionTask;
#end
// NSURLSessionTask+Extras.m
#import "NSURLSessionTask+Extras.h"
#implementation NSURLSessionTask (Extras)
- (void)helloNSURLSessionTask {
NSLog(#"hello NSURLSessionTask!");
}
#end
Everything compiles well, autocomplete works, but when I call this method, my application crashes:
2014-06-27 12:32:23.916 Test[4333:60b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFLocalDataTask helloNSURLSessionTask]: unrecognized selector sent to instance 0x109723310'
Same approach works if I add category to NSObject, and I can't seem to understand why it doesn't for NSURLSessionTask.
Here's a test project which reproduces this problem for me: https://dl.dropboxusercontent.com/u/25100182/Test.zip
Unfortunately it doesn't seem that NSURLSession can support categories. I've run into a problem like that trying to add an associated object.
See also here.
I had similar issue at NSURLSessionDataTask category, when I reduced the scope to NSURLSessionTask it seems to be working correctly.
#interface NSURLSessionTask (iRemoteWallet)
#property (nonatomic, weak) id context;
#end
Hope this helps.
I believe I know what is the origin of this rather odd (to me at least) behaviour. I will provide an example that I've encountered with NSURLSessionDataTask in iOS 9.2.
When you try to use the method that you've added in a category -myMethod: you will see an exception like this:
[__NSCFLocalDataTask -myMethod]: unrecognised selector sent to
instance
I've started digging and discovered that __NSCFLocalDataTask class that hides behind our NSURLSessionDataTask class at runtime is just casted to NSURLSessionDataTask but does not inherit from it. This class inheritance chain is __NSCFLocalDataTask : __NSCFLocalSessionTask : __NSCFURLSessionTask : NSObject. So my category does not apply to this class at all. No wonder it is unrecognised.
One solution to this might be to move your category to NSObject and make a bunch of checking. I did it like this:
if ([self respondsToSelector:#selector(response)]) {
id response = [self performSelector:#selector(response)];
if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
return [NSString stringWithFormat:#"%td", ((NSHTTPURLResponse *)response).statusCode];
}
}
NSException *e =[NSException exceptionWithName:NSInternalInconsistencyException reason:#"errorCode: method should be only used on classes that implement -(NSHTTPURLResponse *)response: method." userInfo:nil];
#throw e;
Ugly? Yes! But it works for now.
I am new to using this method so I could be doing this completely wrong so here is my code:
#property (nonatomic, weak) ConverterViewController *converterViewController;
#property (nonatomic, weak) CalculatorViewController *calculatorViewController;
If I am understanding this code correctly, these are acting as references to Two different ViewControllers.
Then I have this in my viewDidAppear method:
[self addChildViewController:_converterViewController];
[_converterViewController didMoveToParentViewController:self];
[self.view addSubview:_converterViewController.view];
I am getting an NSException at the first line when I try and add it as a child view controller. So not knowing whether or not this should then call some methods in my ConverterViewController class I put some breakpoints within that class both the initWithNibName and viewDidLoad methods and I found that neither of these methods are being called, so Im not exactly sure what is wrong. Then again Im not really sure what could go wrong so any help is greatly appreciated.
This is all I get from the console:
libc++abi.dylib: terminating with uncaught exception of type NSException
Updated Answer:
[self addChildViewController:_converterViewController]; does not create the converterViewController.
It simply takes the converterViewController object and adds it as a childViewController to self.
You will need to allocate memory and instantiate the object converterViewController before -addChildViewController: or else it's value will be nil and nothing will happen.
So... something this:
_converterViewController = [[ConverterViewController alloc] initWithNibName:#"ConverterViewController"
bundle:nil];
//now... adding it as childViewController should work
[self addChildViewController:_converterViewController];
[_converterViewController didMoveToParentViewController:self];
//optional: give it a frame explicitly so you may arrange more childViewControllers
//[_converterViewController.view setFrame:CGRectMake(0,0,100,100)];
[self.view addSubview:_converterViewController.view];
I am trying to get a pop up menu on iPhone.
The main app is using storyboard, but the pop up is a separate xib file that I load:
menu = [[UIViewController alloc] initWithNibName:#"SimpleMenuController" bundle:nil];
[self.view addSubview:menu.view];
and I slide it in and out with animation when pressing a button.
that works fine, but I get a problem when I try to press a button inside that pop up menu
I get the following error:
Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: '-[UIViewController PressCategory:]:
unrecognized selector sent to instance 0x8d3c040'
I have connected the button to PressCategory function
I have connected the view to the file owner.
What I have noticed is that my ViewController is called SimpleMenuViewController, that is where the PressCategory function is, so of course it will not find the selector. But I don't know what I am doing wrong in connecting in the xib file.
Change your code to:
menu = [[SimpleMenuViewController alloc] initWithNibName:#"SimpleMenuController" bundle:nil];
so that you're instantiating the correct class.
Do you have PressCategory function in your SimpleMenuViewController?
If yes, then check weather its parameterized or not.
Declare function in .h file like this:
-(IBAction)PressCategory:(UIButton *)sender;
Define it in .m file like this:
-(IBAction)PressCategory:(UIButton *)sender {
// write your code here
}
Basically I want to get a list of action targets for a UIButton. I have gone through this and my question is slightly different because I do not know what the target is. All I have is a UIButton object. So here's what I did to capture all action targets.
Inspired by below method which works where I get firstResponder object as valid pointer.
UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];
UIView *firstResponder = [keyWindow performSelector:#selector(firstResponder)];
I used class-dump on UIKit to see UIWindow class and I found firstResponder as below.
NS_CLASS_AVAILABLE_IOS(2_0) #interface UIWindow : UIView {
#package
UIResponder *_firstResponder;
}
Then I checked UIControl which via class-dump as
NS_CLASS_AVAILABLE_IOS(2_0) #interface UIControl : UIView {
#package
NSMutableArray* _targetActions;
}
So here's what I try to do and it crashes.
NSMutableArray *arr = (NSMutableArray*)[((UIControl*)btn) performSelector:#selector(targetActions)];
NSLog(#"%#",arr);
Sounds like conspiracy against me. But more likely I am goofing up some thing. Does any know how to access targetActions Array of UIControl?
EDIT: Here's the error message -
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '- [UIRoundedRectButton targetActions]: unrecognized selector sent to instance 0x1c0ab0'
Any help appreciated.
According to the UIControl documentation, the message to send to get a list of targets is allTargets not targetActions as you suggest. The rest of the solution is in the accepted answer to How to get UIButton Target, Action and Control events?
A debugging technique you can use when you don't know what you're doing is to use respondsToSelector to check whether you're sending a message that the object can respond to:
when to use respondsToSelector in objective-c
I'm making a simple calculator and when I use the addition button, the iOS Simulator crashes and I get an NSInvalidArgumentException. What do I do to prevent this from happening?
Error Report:
2013-06-23 17:18:54.574 Tutorial Test (Storyboard)[9744:c07] -[ViewController2 addition]:
unrecognized selector sent to instance 0x75858f0
2013-06-23 17:18:54.577 Tutorial Test (Storyboard)[9744:c07] *** Terminating app due to
uncaught exception 'NSInvalidArgumentException', reason: '-[ViewController2 addition]:
unrecognized selector sent to instance 0x75858f0'
*** First throw call stack:
(0x1c91012 0x10cee7e 0x1d1c4bd 0x1c80bbc 0x1c8094e 0x10e2705 0x162c0 0x16258 0xd7021
0xd757f 0xd66e8 0x45cef 0x45f02 0x23d4a 0x15698 0x1becdf9 0x1becad0 0x1c06bf5 0x1c06962
0x1c37bb6 0x1c36f44 0x1c36e1b 0x1beb7e3 0x1beb668 0x12ffc 0x1e2d 0x1d55)
libc++abi.dylib: terminate called throwing an exception
(lldb)
Code in ViewController that has this error:
View Controller.h
#import <UIKit/UIKit.h>
//Calculator
#interface ViewController2 : UIViewController{
IBOutlet UITextField *textField1;
IBOutlet UITextField *textField2;
IBOutlet UILabel *label;
}
-(IBAction)addition;
-(IBAction)subtract;
-(IBAction)multiply;
-(IBAction)divide;
-(IBAction)clear;
#end
View Controller.m
//Addition
-(IBAction)plus
{
float a = ([textField1.text floatValue]);
float b = a+([textField2.text floatValue]);
label.text = [[NSString alloc] initWithFormat:#"%2.f", b];
}
You named the method in the .m file plus, rather than addition. That is why the method addition isn't found, and the fix would be to rename the method in the .m file from plus to addition:
//Addition
-(IBAction)addition
{
float a = [textField1.text floatValue];
float b = [textField2.text floatValue];
label.text = [[NSString alloc] initWithFormat:#"%2.f", a+b];
}
Have you allocated an instance of the ViewController2 class?
For example:
ViewController2 *vc2 = [[ViewController2 alloc] init];
[vc2 addition];
Also, if the .m code you posted is the full contents of that file, then you're also missing
-(IBAction)addition {
...
}
You didn't inplement the right method.
You call addition but you never actually implement it. Declaring the method signature in the .h is not enough, you have to code the method.
This means that the selector that you are calling is not available on the class you called it against. The best thing to do is place a breakpoint where the method is being called. Go to the debugger and po your object.
po 0x75858f0
in this instance. However that number could be an object and it could be different. Look at the number in the console.
Make sure the object is of the proper class. Then check that class to make sure it responds to the selector you are calling.
Edit: Your problem is that your plus method should be renamed to addition. The names in the .h must match the names in the .m