Programmatically adding switch to scrollview throws exception - iphone

I am using storyboards and have dragged a scrollview window onto a view. In my code I am programmatically creating a switch object that is somehow not being initialized correctly. The switch appears on the view correctly but whenever I click the switch, an exception is thrown saying
"unrecognized selector sent to instance 0x6a786f0'"
I have also attempted to edit the On/Off text to Yes/No and accessing the switch also throws the same exception. Clearly I have missed something in creating my switch and setting the correct delegates or whatever.
My code to create the switch is..
UISwitch *switchControl = [[UISwitch alloc] initWithFrame:CGRectMake(x, y, 60, 20)];
[switchControl addTarget:inputsView action:#selector(actionSwitch:) forControlEvents:UIControlEventTouchUpInside];
[switchControl setBackgroundColor:[UIColor clearColor]];
//[(UILabel *)[[[[[[switchControl subviews] lastObject] subviews]
// objectAtIndex:1] subviews] objectAtIndex:0] setText:#"Yes"];
//[(UILabel *)[[[[[[switchControl subviews] lastObject] subviews]
// objectAtIndex:1] subviews] objectAtIndex:1] setText:#"No"];
[inputsView addSubview:switchControl];
inputsView is the name of my UIScrollView that I created in my .h file.
I should note, when the exception is called on clicking the switch, in the error the 'reason' is reason: '-[UIScrollView actionSwitch:]. When the error is called by trying to adjust the text, the 'reason' is reason: '-[UIImageView setText:]
Any help on what I am missing would be great.
Thanks

The exception is correct, UIScrolView does not have a method actionSwitch:. The target parameter in addTarget: is the object you want to receive the selector: argument.
If your posted code is in the class that has the actionSwitch: method then you would use self as the target, like so:
[switchControl addTarget:self action:#selector(actionSwitch:) forControlEvents:UIControlEventTouchUpInside];
And as a side note. For a UISwitch you generally want your method called for UIControlEventValueChanged, that way if the user just touches the switch but doesn't "switch" it your method won't be called.
Edit in response to: "I just tried changing to 'self' for the UISwitch and the error still occurs. I haven't created an actionSwitch method."
Yes, your application would still crash because whatever you pass in as the target must implement the selector/method passed in as the selector.
The view controller is the ideal place to implement this method. A very standard implementation of this event target would look like:
-(void)actionSwitch:(UISwitch *)theSwitch{
if (theSwitch.isOn){
// Switch was switched on respond accordingly
}
else {
// Switch was switched off respond accordingly
}
}

Related

How to use Custom Picker View with search bar in ios

I am beginner in iOS In one of my activity I have created custom picker view with search bar .....Actually I am using YHCPicker class for custom picker view and search bar and apply this on TextField Code here.....
UITextField* StateId;
StateId=[[UITextField alloc]initWithFrame:CGRectMake(150,540,150,30)];
StateId.font = [UIFont boldSystemFontOfSize:12.0];
StateId.borderStyle = UITextBorderStyleLine;
StateId.delegate = self;
StateId.tag = 4;
[scrollview addSubview:StateId];
and I am using this delegate for this textfield....
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
if (textField.tag==4)
{
View_StateID = [[NSMutable Array]allocinitWithArray:#"Delhi", #"Rajasthan"......, nil];
NSLog(#"dict is %#",View_StateID);
PickerView* objYHCPickerView = [[PickerView alloc] initWithFrame:CGRectMake(0, 0, 320, 480) ];
objYHCPickerView.delegate = self;
[self.view addSubview:objYHCPickerView];
[objYHCPickerView showPicker:View_StateID];
}
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
return YES;
}
then call method ShowPicker in YHCPickerView and I show this picker with search bar on my view.....like as image
Now in this image when we search in search bar first time then get desired state successfully and click on done or search button(from keybord) then get value on StateID textfield but when we again tap on text field then my image as well as but tap on searchbar then get error like this....
-[CALayer keyboardWillShowNotification:]: unrecognized selector sent to instance 0xaad8950
So I don't know what problem ....so solve this problem...
Errors like this can be caused by non properly retaining objects:
The object is released and freed.
Its memory is reused for some random other object.
Then, when a selector is called on the original object -> boom.
One thing to check is if all your #properties that hold objects in your class are strong and not assign.
What's also smart to do is setting an exception breakpoint
Finally, try to find out to which object this pointer 0xaad8950 (did) belong(s): Place breakpoints further and further, before the app crashes and look around at the objects' address you're having.
Good luck!

iOS memory management error - message sent to deallocated instance

I created many buttons before, but for some reason I'm having trouble creating a simple button.
In my viewDidLoad method I created a very basic button:
_button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
_button.frame = CGRectMake(0, 0, 100, 25);
[_button addTarget:self action:#selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:_button];
- (void)buttonClicked:(id)sender
{
NSLog(#"%#", sender);
NSLog(#"Download issue");
}
But for some reason when I click on it I'm just getting an error
* -[DownloadButtonViewController performSelector:withObject:withObject:]: message sent to deallocated instance 0x6ac2af0
I have no idea what's going wrong as the code is exactly the same as every button I created before ... (probably just having a bad day ...)
Your view controller itself is being deallocated. Maybe you're using ARC and you don't have a strong reference to your view controller, so it's deallocated immediately after creation.
I have just Copy pasted your code and it's working fine here,it might be possible you are realeasing it some where by mistake because that object is Autoreleased it self and H2CO3 as said is also true.

How do you initialize a UIGestureRecognizer?

I want to add a gesture recognizer to my button so that I can run code if the user swiped past the buttons frame. I also want this code to be different if the swipe was up, right, left, or down the button.
-(void)viewDidLoad
{
[super viewDidLoad];
UIButton *button=[UIButton buttonWithType:UIButtonTypeRoundedRect];
button.frame=CGRectMake(0, 0, 100, 100);
[self.view addSubview:button];
UIGestureRecognizer *swipe=[[UIGestureRecognizer alloc]initWithTarget:button action:#selector(detectSwipe)];
[button addGestureRecognizer:swipe];
}
so, did I do the initWithTarget:action: thing correct? And now that I do this how do i Implement the detectSwipe method?
here is my idea on how to implement detectSwipe
-(IBAction)detectSwipe:(UIButton *)sender
{
/* I dont know how to put this in code but i would need something like,
if (the swipe direction is forward and the swipe is > sender.frame ){
[self ForwardSwipeMethod];
} else if //same thing for right
else if //same thing for left
else if //same thing for down
}
No, it isn't correct. The target of the gesture recognizer is not the button, it's the object on which it calls the action method when detecting a gesture (otherwise how would it know on which object call that method? In OO, a method call/message send needs an explicit method name and an instance or class).
So you would most likely want
recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(didSwipe:)];
You also don't create an instance of UIGestureRecognizer directly but one if its concrete subclasses, UISwipeGestureRecognizer in this case.
After alloc-initting the recognizer, you attach it to the view you want to be recognized:
[button addGestureRecognizer:recognizer];
Then in the didSwipe: method, you can use the gesture recognizer's properties to decide what the size/distance/other property of the swipe was.
You better read some docs next time.
You probably want to be using a UISwipeGestureRecognizer. UIGestureRecognizer usually shouldnt be used unless you are subclassing it. Your code should look similar to the following.
UISwipeGestureRecognizer *swipe=[[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(detectSwipe)];
swipe.direction = UISwipeGestureRecognizerDirectionRight;
[button addGestureRecognizer:swipe];
You got all right except for the target of gesture recogniser. The target is an object that receives given selector message so your initWithTarget: call should accept self as an argument unless you're implementing detectSwipe method in a subclass of your button.
H2CO3's answer is complete. Just don't forget that you're missing a colon ":" at the end of your selector! It should be like this: #selector(detectSwipe:)
The colon ":" is because your method has an argument: (UIButton *)sender

How can I safely memory manage a button that I want to remove from the UI?

I'm making an app that is kinda like iBooks. There is some stuff on the screen, each item represented by a small thumbnail. I want the user to be able to delete the items much like when you tap the "Edit" button in iBooks - an X comes up, and the item is deleted. I'm using the delegation pattern to handle all of this, so here is some code:
// Button is created in CustomView.h class
UIImage *deleteImage = [UIImage imageNamed:#"delete.png"];
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
self.deleteButton = button;
[self.deleteButton setImage:deleteImage forState:UIControlStateNormal];
[self.deleteButton addTarget:self action:#selector(deleteIt) forControlEvents:UIControlEventTouchUpInside];
// Here's what's called when the delete button is pushed
- (IBAction)deleteMap {
[self.customViewDelegate itemWasDeleted:self];
}
// And here's the implementation of that method, in a View Controller
- (void)itemWasDeleted:self:(CustomView*)customView {
// delete domain object
// . . .
[self.collectionOfCustomViews removeObject:customView];
[customView removeFromSuperview];
}
The problem with this code is that I get a Bad Access Exception. Via NSZombie, looks like this:
* -[UIButton _unhighlight]: message sent to deallocated instance 0x5f4a740
I guess what's happening is that when my target-action implementation is called, it's not yet safe to release the button, as I'm doing in my delegate method. So my question is, what's a better approach to doing this so that may app doesn't crash? I'd like to know the cleanest approach possible.
If collectionOfCustomViews was the only object retaining customView then you released it when you removed it, so it can't respond to removeFromSuperview.

UIControl subclass is unable to take a target?

I've subclasses UIControl and in it I am sending:
[self sendActionsForControlEvents:UIControlEventValueChanged];
When I create an instance of the object, I add a target as follows:
[starView addTarget:self action:#selector(starRatingChanged:) forControlEvents:UIControlEventValueChanged];
The view shows up fine, and without the target being there the functionality works well. But with adding the target, it crashes. Any ideas why?
My class is declared with:
#interface RMStarRating : UIControl {...}
For what it is worth, I set up my view in - (void)layoutSubviews. Is there another method that I need to subclass in order for the targets to be saved properly or for the targets to be sent the right actions? I thought UIControl handled saving the targets and actions for you.
UPDATE: trying to provide more information
I set the object up as follows:
RMStarRating *starView = [[RMStarRating alloc] initWithFrame:CGRectMake(10, 70, 23*5, 30)];
[starView addTarget:self action:#selector(starRatingChanged:) forControlEvents:UIControlEventValueChanged];
....
[self.view addSubview:starView];
My sendAction, according to Jordan's suggestion:
- (void)sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event {
NSLog(#"send action");
[super sendAction:action to:target forEvent:event];
}
My function that calls sendActionsForControlEvents:
- (void)updateValue:(UITouch *)touch {
....
NSLog(#"sendActionsForControlEvents");
[self sendActionsForControlEvents:UIControlEventValueChanged];
}
And the function that should be called (and it is in the header too):
- (void)starRatingChanged:(id)sender {
NSLog(#"star rating changed");
}
And the log just spits out:
2010-10-22 09:45:41.348 MyApp[72164:207] sendActionsForControlEvents
2010-10-22 09:45:41.350 MyApp[72164:207] send action
The debugger has:
Have you tried implementing
- (void)sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event
instead? A good example is located here:
Can I override the UIControlEventTouchUpInside for a UISegmentedControl?
Ok, I figured out what it was. I was releasing my parent class too soon, so there was no object for the message to be sent back to, even though it was showing on screen.
And I ended up not needing the sendAction:to:forEvent.
Jordan, thanks you for your help.