How does sender.selected = ! sender.selected toggle between selected states? - ios

I'm very new to Objective-C so sorry if this is extremely obvious to many of you, but I'm trying to work out how the following piece of code is actually working:
- (IBAction)chooseColour:(UIButton *)sender {
sender.selected = !sender.isSelected;
}
Now it obviously toggles between the selected and unselected states of the button sending the action, but what is the code 'sender.selected = !sender.isSelected' actually saying? Is it just 'set the sender selected property to the opposite (i.e. ! not) of the getter'? So if the getter is 'getting' the current selected value as true then it sets the selected property as !true i.e false. Or is this a piece of convenience code that I'm not yet privy to? Because it also seems that '!sender.isSelected' simply means not selected as in
if (!sender.isSelected){
statement
}
i.e. do statement if the sender is not selected. This is no doubt really obvious, just I'm a bit confused with it at the moment.
Thanks!

You are entirely correct, it's calling the getter to obtain the value and calling the setter with the NOT (!) of the value. It isn't Objective-C, it's plain C syntax.

Is it just 'set the sender selected property to the opposite (i.e. ! not) of the getter'?
Exactly. That.
Or is this a piece of convenience code that I'm not yet privy to?
No, the only piece of syntactic sugar is the dot notation for getters/setters, but you are already aware of it.

The portion of the code:
sender.selected = !sender.isSelected;
Basically inverts the selection. It asks the question Is this false? so true evaluates false, and false evaluates to true. So it's a toggle.

from documentation :
#property(nonatomic,getter=isSelected) BOOL selected; // default is NO may be used by some subclasses or by application
//explanation
if you use ![sender isSelected] value in property isn't changed. then if you use setter sender.selected = ![sender isSelected] - new value is set to the sender (selected property). then run getter sender isSelected return new value, uff i hope it helps

Related

Set bool property of all objects in the array

I've a model class called PhotoItem. In which I have a BOOL property isSelected
#interface PhotoItem : NSObject
/*!
* Indicates whether the photo is selected or not
*/
#property (nonatomic, assign) BOOL isSelected;
#end
I've an NSMutableArray which holds the object of this particular model. What I want to do is, in a particular event I want to set the bool value of all objects in the array to true or false. I can do that by iterating over the array and set the value.
Instead of that I tried using:
[_photoItemArray makeObjectsPerformSelector:#selector(setIsSelected:) withObject:[NSNumber numberWithBool:true]];
But I know it won't work and it didn't. Also I can't pass true or false as the param in that (since those are not object type). So for fixing this issue, I implemented a custom public method like:
/*!
* Used for setting the photo selection status
* #param selection : Indicates the selection status
*/
- (void)setItemSelection:(NSNumber *)selection
{
_isSelected = [selection boolValue];
}
And calling it like:
[_photoItemArray makeObjectsPerformSelector:#selector(setItemSelection:) withObject:[NSNumber numberWithBool:true]];
It worked perfectly. But my question is, Is there any better way to achieve this without implementing a custom public method ?
Is there any better way to achieve this without implementing a custom public method?
This sounds like you are asking for opinion, so here is mine: Keep it simple.
for (PhotoItem *item in _photoItemArray)
item.isSelected = YES;
Why obfuscate a simple thing with detours through obscure methods when you can write code that anybody will immediately understand?
Another way of doing the same thing would be:
[_photoItemArray setValue:#YES forKey:#"isSelected"];
This does not need the custom additional setter method because KVC does the unboxing for you.
But again I would vote against using such constructs. I think they are distracting from the simple meaning and confusing developers that come after you.

Could not find an overload for '=='

I have the following code:
var settingButton:UIButton
settingButton = appDelegate.myFunctionReturningButton()
if (settingButton == nil) {println("WE ARE IN BAD SHAPE!!!!")}
It partly works, but not always. To see what happens in case I do not get what I expect from myFunctionReturningButton(), I added the last line.
But here is the problem and my question:
I get this error message from the Swift compiler:
Could not find an overload for '==' that accepts the supplied arguments
Browsing the net, I kind of understand what that means, but what can I do about it?
How should I write the last line?
For precision:
I have the two following function in AppDelegate.swift and appSettingButton is declared with this line at the top of the AppDelegate class.
var appSettingButton: UIButton = UIButton.alloc()
func registerSettingButton (button:UIButton) {
appSettingButton = button
}
func myFunctionReturningButton() -> UIButton {
return appSettingButton
}
You can't compare a non-optional value to nil because it will never be nil. And you shouldn't use UIButton.alloc() to initialize a button, just use UIButton(). If your logic depends on waiting for this button to be re-defined after initialization of your app delegate subclass, you should make an optional, i.e. UIButton?. Then you can compare it to nil.

How can I get the opposite value of a Bool in Swift?

My specific case is I am trying to toggle the nav bar hidden and showing.
let navHidden = !self.navigationController?.navigationBarHidden
self.navigationController?.setNavigationBarHidden(navHidden!, animated: true)
Is not working for me like it normally would in Obj-C.
The exclamation point is on the wrong side of the boolean. The way you've written it would indicate that the boolean could be nil. You want !navHidden.
navHidden! is to make sure this is not optional. !navHidden is the correct way to do that.
From Apple's book.
Trying to use ! to access a non-existent optional value triggers a runtime error. Always make sure that an optional contains a non-nil value before using ! to force-unwrap its value.
navHidden is an optional. And you explictely unwrap that optional (which means you get a crash if navHidden is nil). Clearly something is wrong here. I suggest
if let navController = self.navigationController {
let navHidden = navController.navigationBarHidden
navController.setNavigationBarHidden (!navHidden, animated:true)
}

Pass different parameters to an IBAction

My iPhone app has many buttons and I want all the buttons to call the same method, but with different parameters.
For example I want tapping one button to call the method myMethod: with the argument #"foo", and a second button should call the same method but with argument #"bar".
The so called "IBActions" must have one of these signatures:
-(void)action;
-(void)actionWithSender:(id)sender;
-(void)actionWithSender:(id)sender event:(UIEvent*)event;
You cannot add any other parameters. Nevertheless you can use sender (which is button1 or button2 in your case) to get the parameter:
-(void)actionWithSender:(UIButton*)sender {
NSString* parameter;
if (sender.tag == 1) // button1
parameter = #"foo";
else // button2
parameter = #"bar";
...
}
the real reason You cannot add additional parameter is that UIKIT will push params on the stack.
so the only way is to use tags.
A DIRTY way can be to convert a pointer to int and tagging the button with it:
myStruct params;
// fill params:
params.x=....
params.y=....
params.z=....
UIButton * btn = [UIButton......]; // create or use one from XIB
btn.tag = (int)&params;
... in Call back:
-(IBActions) doIt:(id)sender
{
myStruct * paramsPtr = (myStruct*)tag;
int i = paramsPtr->x;
NOTE: params MUST be keep static .. or allocate using malloc (more and more ugly code...).
DO NOT use a local var: it will be allocated on stack so will be removed after exiting from the setup method.
Give your various UIButton instances different tag property values.
In your IBAction method -myMethod:, you might then do something like:
- (void) myMethod:(id)sender {
switch (sender.tag) {
case (firstButtonTag):
doFooStuff;
break;
case (secondButtonTag):
doBarStuff;
break;
// etc.
}
}
The values firstButtonTag and secondButtonTag can be stored in an enum if you want to make this easy to maintain.
You can't pass parameters through an IBAction. What I usually do is give the buttons the unique tag in IB. THe tag is an integer value so I u then use a simple lookup table to convert the tag to some value.
In this case, three buttons but tags 1 to 3:
- (IBAction) buttonPressed: (UIButton*) sender
{
static const NSString* names = { #"Foo", #"Bar", #"Baz" };
id tag = [sender tag];
if (tag >= 1 && tag <= 3) {
NSLog(#"Button pressed is %#", names[tag]);
}
}
(id)Sender is shows that whatever u pass on UIButton click event is directly pass to this method and no matter that what type it is , it take automatically like if you pass button tag then it take button tag as sender.tag etc
As others have mentioned you cannot pass your custom parameter into action method. If you do not like the solution using tags you may also subclass UIButton with your custom class and add your parameter there. (By I wouldn't bother and just use tags)
You don't. The only parameter is the sender object, which you may use to have a different behavior, but what I'd do is define 2 action methods, which simply in turn call the same method with a different parameter, i.e. you'd have:
- (IBAction)button1:(id)sender
{
[self doStuff:kButton1];
}
- (IBAction)button2:(id)sender
{
[self doStuff:kButton2];
}
- (void)doStuff:(ParamType)param;
{
...
}
In defense of that method (no pun intended), I'd add that it makes clearer when you review your UI with Interface Builder to see that different buttons actually have different effects, which is harder to tell if they all call whateverAction:

Problem setting property value on Custom Control Template Part

I have a custom control template that contains a Slider control.
I name that as a part in the class that implements the custom control:
[TemplatePart(Name = MapZoomSliderName, Type = typeof(Slider))]
In the OnApplyTemplate() override, I get the Slider:
MapZoomSlider = (Slider) GetTemplateChild("MapZoomSlider");
if (null != MapZoomSlider)
{
MapZoomSlider.ValueChanged +=new RoutedPropertyChangedEventHandler<double>(MapZoomSlider_ValueChanged);
MapZoomSlider.Value = InitSliderValue; // crash
_lastSliderValue = MapZoomSlider.Value;
}
When I try to set the Slider's Value property, the app crashes with "Object reference not set to an instance of an object."
Getting the slider's value works as expected.
What do I need to do to set the Slider's value at run time?
Thanks for any tips...
What is "InitSliderValue"? Maybe its the wrong value type? (Must be a double) Also, zero or negative may not be a valid value.
It appears the problem was in setting the ValueChanged handler before changing the Value property. The ValueChanged handler tries to manipulate other parts of app, parts that might not be ready yet.
If I set the value, then add the handler, it works as desired.
MapZoomSlider.Value = InitSliderValue; // all good
MapZoomSlider.ValueChanged +=new RoutedPropertyChangedEventHandler<double>(MapZoomSlider_ValueChanged);

Resources