I have three methods which are taking parameters,
I am taking exception at this parameter giving,
[QuestionnaireView continueSingle:withQuestion:question:]: unrecognized selector sent to instance 0x8a4b1c0
What am i doing wrong? Its definition is also given in the header file.
Here is my code;
-(void) continueSingle:(id)sender withQuestion:(Question*)quest{
int counter = 0;
NSString * tempAnswer;
for(UIView* subview in [sender superview].subviews)
{
if([subview isKindOfClass:[UIButton class]])
{
if([((UIButton*)subview) isSelected])
{
counter++;
tempAnswer = [NSString stringWithFormat:#"%#",((UIButton*)subview).currentTitle];
}
}
}
}
Your mistake is here
-(void) continueSingle:(id)sender withQuestion:(Question*)quest
Because you are passing three parameter but you're receiving only two parameter. So you need to take 3 parameter. Like this..
-(void) continueSingle:(id)sender withQuestion:(Question*)quest question:(Question *)question1
Related
Please can anyone tell me why this piece of code isn't working? I've got a dictionary which contains UIViews with tables inside associated with the keys which are the names of the corresponding buttons (there are a lot of them). So what I actually want to do is to change the view visibility on the corresponding button click. But the issue is that the expression to do that is not accepted by Xcode and I get the Expected Identifier error.
- (IBAction)choosingButtonClicked:(id)sender {
if ([sender currentTitle]) {
[(UIView *)[self.selectionTables objectForKey:[sender currentTitle]]].hidden = ![(UIView *)[self.selectionTables objectForKey:[sender currentTitle]]].isHidden;
}
}
First of all, with all due respect, I agree with trojanfoe comments. Its not working because its not properly written.
Now, lets try to streamline it with below code:
- (IBAction)choosingButtonClicked:(id)sender {
NSString *title = [sender currentTitle];
if (title) {
UIView *selectionView = (UIView *)self.selectionTables[title];
selectionView.hidden = !selectionView.isHidden;
}
}
Your code is too complex, because of that even the author can't understand it. If we re-write your code using local variables, it will look like:
- (IBAction)choosingButtonClicked:(id)sender
{
NSString *title = [sender currentTitle];
if (title)
{
UIView *tempView = (UIView *)[self.selectionTables objectForKey:title];
[tempView].hidden = ![tempView].isHidden;
}
}
If you check the code now, you can see that the following code is causing the issues:
[tempView].hidden = ![tempView].isHidden;
Change your method like:
- (IBAction)choosingButtonClicked:(id)sender
{
NSString *title = [sender currentTitle];
if (title)
{
UIView *tempView = (UIView *)[self.selectionTables objectForKey:title];
tempView.hidden = !(tempView.isHidden);
}
}
Following code of mine generates crash in ARC mode:
MxTextField.m
+enableAllTextFields:(BOOL)enable InViews:(__weak UIView*) view
{
#try
{
NSArray* textFields = view.subViews;
for(int idx = 0; idx < textFields.count; idx++)
{
__weak UIView* view = [textFields objectAtIndex:idx];
if(view.subViews.count > 0)
[MxTextField enableAllTextFields:enable InView:view];
else
NSLog(#"No SubViews");
if([view class] == [MxTextField class])
[(MxTextField*) view setEnabled:enable];
}
}
#catch(NSException exception)
{
NSLog(#"%s : %#",__func__,exception);
}
}
After Some Loop on the execution of this function It crashes by showing breakpoint at the end of the function saying EXC_BAD_ACCESS. Can anyone help me out that what goes wrong in this implementation?
Any help will be thankful.
Putting aside many other problems the only reason for a crash that I can see from the posted code is that your method is supposed to return an object but does not do so.
Explanation: While it's not common to leave out the return type in Objective-C it's perfectly legal. It means that the method returns an object of type id.
Since your method lacks a return statement the returned value is undefined. This confuses ARC and probably makes it autorelease the random value in the return register which, eventually, leads to the crash.
Here's a proper version of your method:
+ (void)forAllTextFieldsIn:(UIView *)view setEnabled:(BOOL)enabled
{
if ([view isKindOfClass:[MxTextField class]])
[(MxTextField *)view setEnabled:enabled];
for (UIView *subview in view.subviews)
[self forAllTextFieldsIn:subview setEnabled:enabled];
}
The problem could be the method adopted for iteration and also try-catch is not a good practice, use fast-enumeration for faster and reliable result . The below code could resolve your problem
+(void)enableAllTextField:(BOOL)enable inView:(UIView *)contrainerView
{
for (UIView *subview in contrainerView.subviews) {
if(subview.subviews.count>0)
[MxTextField enableAllTextField:enable inView:subview];
else if ([subview isKindOfClass:[MxTextField class]]) {
MxTextField *textField = (MxTextField *)subview;
[textField setEnabled:enable];
}
}
}
My program kept terminating due to an uncaught exception. The keyboard works fine until a character is entered on the keyboard.
I have a button to bring up the keyboard and an outlet hooked up to a text field, I'm also the text field delegate.
[code removed]
Thank you in advance for any help :)
This line lbl.text=TempTF.text; is not good in your case. Your lbl can be any type of UIView since you just typecast it from subviews. So in your case one of them is a type of UIRoundedRectButton which has no setter for text.
You need to put some if([lbl isKindOfClass:]) or do a check if([lbl respondsToSelector:#selector(setText:)])
-(void)changeLabelsMethod:(UITextField*)txtField
{
NSArray *allLabelViews = self.view.subviews;
for(id subView in allLabelViews) {
if([allLabelViews isKindOfClass:[LettersOnTileView class]])
{
for (int i = 0; allLabelViews.count>0; i++) {
LettersOnTileView.tag = i;
if([[allLabelViews objectAtIndex:i] isKindOfClass:[UILabel Class]]){
UILabel *lbl=[allLabelViews objectAtIndex:i];
lbl.text=TempTF.text;
}
}
}
}
You have issue in your code.
Instead of this code.
for(id subView in allLabelViews) {
if([allLabelViews isKindOfClass:[LettersOnTileView class]])
{
You have to try this.
for(id subView in allLabelViews) {
if([subView isKindOfClass:[LettersOnTileView class]])//Here you want to check all subview .
{
2) I think you have got button object in this line UILabel *lbl=[allLabelViews objectAtIndex:i];. That's y it get crashed logged in next line.
With the following setup
....
MyUIMenuItem *someAction = [[MyUIMenuItem alloc]initWithTitle : #"Something" action : #selector(menuItemSelected:)];
MyUIMenuItem *someAction2 = [[MyUIMenuItem alloc]initWithTitle : #"Something2" action : #selector(menuItemSelected:)];
....
- (IBAction) menuItemSelected : (id) sender
{
UIMenuController *mmi = (UIMenuController*) sender;
}
How to figure out which menu item was selected.
And don't say that you need to have two methods... Thanks in advance.
Okay, I've solved this one. The solution isn't pretty, and the better option is "Apple fixes the problem", but this at least works.
First of all, prefix your UIMenuItem action selectors with "magic_". And don't make corresponding methods. (If you can do that, then you don't need this solution anyway).
I'm building my UIMenuItems thus:
NSArray *buttons = [NSArray arrayWithObjects:#"some", #"random", #"stuff", nil];
NSMutableArray *menuItems = [NSMutableArray array];
for (NSString *buttonText in buttons) {
NSString *sel = [NSString stringWithFormat:#"magic_%#", buttonText];
[menuItems addObject:[[UIMenuItem alloc]
initWithTitle:buttonText
action:NSSelectorFromString(sel)]];
}
[UIMenuController sharedMenuController].menuItems = menuItems;
Now your class that catches the button tap messages needs a few additions. (In my case the class is a subclass of UITextField. Yours might be something else.)
First up, the method that we've all been wanting to have but that didn't exist:
- (void)tappedMenuItem:(NSString *)buttonText {
NSLog(#"They tapped '%#'", buttonText);
}
Then the methods that make it possible:
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
NSString *sel = NSStringFromSelector(action);
NSRange match = [sel rangeOfString:#"magic_"];
if (match.location == 0) {
return YES;
}
return NO;
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
if ([super methodSignatureForSelector:sel]) {
return [super methodSignatureForSelector:sel];
}
return [super methodSignatureForSelector:#selector(tappedMenuItem:)];
}
- (void)forwardInvocation:(NSInvocation *)invocation {
NSString *sel = NSStringFromSelector([invocation selector]);
NSRange match = [sel rangeOfString:#"magic_"];
if (match.location == 0) {
[self tappedMenuItem:[sel substringFromIndex:6]];
} else {
[super forwardInvocation:invocation];
}
}
One would expect that the action associated with a given menu item would include a sender parameter that should point to the chosen menu item. Then you could simply examine the title of the item, or do as kforkarim suggests and subclass UIMenuItem to include a proeprty that you can use to identify the item. Unfortunately, according to this SO question, the sender parameter is always nil. That question is over a year old, so things may have changed -- take a look at what you get in that parameter.
Alternately, it looks like you'll need to a different action for each menu item. Of course, you could set it up so that all your actions call a common method, and if they all do something very similar that might make sense.
Turns out it's possible to obtain the UIButton object (which is actually UICalloutBarButton) that represents UIMenuItem if you subclass UIApplication and reimplement -sendAction:to:from:forEvent:. Although only -flash selector goes through UIApplication, it's enough.
#interface MyApplication : UIApplication
#end
#implementation MyApplication
- (BOOL)sendAction:(SEL)action to:(id)target from:(id)sender forEvent:(UIEvent *)event
{
// target == sender condition is just an additional one
if (action == #selector(flash) && target == sender && [target isKindOfClass:NSClassFromString(#"UICalloutBarButton")]) {
NSLog(#"pressed menu item title: %#", [(UIButton *)target titleLabel].text);
}
return [super sendAction:action to:target from:sender forEvent:event];
}
#end
You can save target (or any data you need from it) in e.g. property and access it later from your UIMenuItem's action.
And to make your UIApplication subclass work, you must pass its name as a third parameter to UIApplicationMain():
int main(int argc, char *argv[])
{
#autoreleasepool {
return UIApplicationMain(argc, argv, NSStringFromClass([MyApplication class]), NSStringFromClass([YOUR_APP_DELEGATE class]));
}
}
This solution works on iOS 5.x-7.0 as of post date (didn't test on older versions).
ort11, you might want to create a property of myuimenuitem and set some sort of Tag. Thay way the object of sender could be recognized by its tag it. In Ibaction then you can set a switch statement that can correspond to each sender.tag and work throught that logic. I guess thats the simplest way to go.
The following will pass the respondsToSelector test, but SIGABRT on the actual call to [viewController selector] or [viewController action:selector]. The stack trace states 'NSInvalidArgumentException, reason: -[MyViewController selector]: unrecognized selector'.
[viewController #selector(selector)] will cause a compile error (error: expected ':' before 'selector').
When the selector is hard coded, all works well.
How do I send a message to an object through a selector?
-(void) notifyViewControllers:(NSString*) message
{
if(!message) return;
SEL selector = NSSelectorFromString(message);
if(!selector) return;
NSArray* viewControllers = [self.tabBarController viewControllers];
if(!viewControllers) return;
for (UIViewController* viewController in viewControllers)
{
if(!viewController) continue;
if ([viewController respondsToSelector:selector]) {
// [viewController selector];
[viewController action:selector];
}
}
}
[self performSelector:#selector(notifyViewControllers:) withObject: message];
Try
[viewController performSelector:selector];
Also check other methods NSObject in performSelector 'family' - with them you can easily call selector with delay and/or on background thread.
Could be useful to know how to do this where you cannot use performSelector, maybe because the selector string must be used within a protocol method:
In order to allow the selector supporting parameters, it should be specified as follow:
NSString *stringForSelector = #"doSomethingAwesome:"; // notice the colon
Let's say we're going to handle a tap gesture
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:NSSelectorFromString(stringForSelector)];
UIGestureRecognizer class allow to use the recognizer itself in the action callback:
- (void)handleGesture:(UIGestureRecognizer *)gestureRecognizer;
So to do something awesome on Tap, we could write:
- (void)doSomethingAwesome:(UITapGestureRecognizer *)tapGesture
{
// gesture handling with UIGestureRecognizer availability
}