I'm trying to create an iPad/iPhone app that dynamically creates menus depending on a JSON object that is returned from a RESTful API. Specifically I'm trying to show/hide a UIPickerView that I created using the interface builder. In the properties menu in the interface builder I checked the box "hidden" for that UIPickerView. I used this tutorial to create to UIPickerView. I've set the delegate and data source to the View Controller using the interface builder. I'd like to unhide/show the UIPickerView when a certain condition is met. So far I've tried the following code:
[self.choicePicker setHidden:NO];
self.choicePicker.hidden = NO;
I usually build such object programmatically but I thought I'd try it this way. I've looking through various stackoverflow posts and doing research but I can't seem to find something that works. I'm new to programming in Objective C. Thanks in advance any help is greatly appreciated.
.h file code
#interface slrpViewController : UIViewController<UITextFieldDelegate, UIPickerViewDelegate, UIPickerViewDataSource>
{
IBOutlet UIPickerView *picker_choice;
NSMutableArray *dataArray;
NSMutableData *receivedData;
}
#property(nonatomic, strong) UILabel *nameLabel;
#property(nonatomic, retain) UIPickerView *choicePicker;
.m file code
-(void)buildChoicesMenu:(NSDictionary *)choiceDict{
//in this method we build the choices menu
[self.choicePicker setHidden:NO];
self.choicePicker.hidden = NO;
if (self.choicePicker) self.choicePicker.hidden = !self.choicePicker.hidden;
}
You have two different picker views defined. One a property choicePicker (and an implicit _choicePicker instance variable), and another instance variable picker_choice. It seems you have connected your picker_choice in interface builder, but are trying to modify the property. In fact, if you try to print po self.choicePicker in the debugger, you would get nil, because there is nothing filling it.
Either remove the instance variable, and connect your property in interface builder, or synthesize your property with your instance variable by doing so:
#syntesize choicePicker=picker_choice
Related
There are at least 3 methods of creating an IBOutlet in Objective-C, for making iOS 10 App, in Xcode 8.
Method 1: in ViewController.h
#interface ViewController : UIViewController
#property (nonatomic, strong) UILabel *textLabel;
#end
Method 2: in the interface of ViewController.m
#interface ViewController () {
IBOutlet UILabel *textLabel;
}
#end
Method 3: in the interface of ViewController.m, using #property
#interface ViewController ()
#property (nonatomic, strong) UILabel *textLabel;
#end
Given that the textLabel has to be accessed & its text is needed to be updated frequently, which method is the correct way to do so?
That all depends on whether you need your outlet to be accessible to classes outside of the containing one; generally I would discourage this because it is good practice to keep your view controllers responsible for updating your UI and not pass this task around to other classes. With this being said, Method 3 would be the best option, however, if you do have to access your object from another class, then simply use Method 1 so it is exposed in your class header.
Method 2 utilises iVars rather than object properties and is not the proper way to declare outlets, it may even cause unexpected behaviour so it is best to avoid this method.
Your code contains no proper IBOutlet. Outlets are connections to Storyboard.
Method 1
This is a property. As it is in .h file, it can be reached from outside. The Objective-C pattern for public.
Method 2
This is an iVar. Do not use iVars if you do not have to.
Method 3
This is a property. As it is in .m file, it can not be reached from outside. The Objective-C pattern for private.
Method 4
A proper IBOutlet looks like this:
#interface ViewController ()
#property (nonatomic, weak) IBOutlet UILabel *label;
#end
It is a simple property. You have to decide if you put it in .h or .m file depending on whether or not you want to publish it.
The IBOutlet simply makes the property connect-able to Storyboard. It's an annotation for Xcode and does not alter the semantic of your code.
Edit 1:
As Sulthan correctly mentions in the comments:
In most situations the correct design pattern is to hide outlets because it's an implementation detail. External classes should not set data directly using views.
Edit 2:
Why "not to use iVars if you do not have to" (2)
Opinion based:
I consider it as good OOP practice to use getters & setters (and thus not to access the variables directly). Also code is easier to read as you know while reading what x = self.variable (property) and x = variable (local variable) are.
If you have to use iVars for some reason, it is common to (and I would recommend to) prefix the name with _. x = _variable (iVar).
I've got a handful of UIViews subclasses as a part of my interface and I'm looking for an easy human readable way to differentiate them in the code -- like the label you set in the "Document" section of the UI editor.
I believe the "Accessibility Label" is exposed, but that doesn't seem like the correct use of that variable.
Am I stuck documenting which Object ID each object has or is there a more intelligible way?
There are lots of ways to do what you want to be done. Here are several of them:
#properties
The first thing that came to my mind are properties. Use your view controller as a storage class by adding following property declarations in your header file:
#property (nonatomic, weak) IBOutlet UIView *myFantasticView;
#property (nonatomic, weak) IBOutlet UIView *myGorgeousView;
...
Then, just simply connect your views to specific outlets in Interface Builder.
The only drawback is that you will have to declare a lot of properties which can become a little confusing.
Custom runtime attributes (another use of #properties)
If you're using UIView's subclasses (I assume you do), you can use your UIView subclass and declare an "identifier" property:
#interface MyView : UIView
#property (nonatomic, strong) NSString *myViewID;
...
#end
Then, assign this value using code (simple property setting) or in Interface Builder:
Now you can identify your views using one of those method. But remember that you can come up with a better, more suitable solution! :)
I'm basically an Android programmer and on my way to learning some skills on iOS platform.
I have an Android application, which has a custom UI component which looks like
.
I want to create a similar re-usable UI component for my sample iOS application. I'm not able to get any lead on how to do this in iOS.
On Android I can create a composite UI element using a layout file but in iOS i'm not sure if i can create a composite UI element or extend UIView and then somehow layout Text and image components inside it.
I'm looking for some leads on implementing this. I plan to have a multiple instances of these component on screen & the values gets updated from a web service.
I recommend something called interface builder in iOS.
It is a place where you can visually place elements that the user interacts with and you can see how the design looks as you layout your structure.
For tutorials, you can look at http://mobile.tutsplus.com/tutorials/iphone/interface-builder/
or search up "ios xib tutorial"
Hope this helped!
If you want it to be a simple view, then you could create a UIView sub-class with a few UITextFields's and probably an UIImageView or two that all have outlets so that your controller can make changes to it. For instance:
#interface StockInfo <UIView>
#property (nonatomic, strong, readonly) UITextField *ticker;
// You may want to make these numbers so that you can do calculations with them, and then update the text field automatically
#property (nonatomic, strong, readonly) UITextField *price;
#property (nonatomic, strong, readonly) UITextField *priceChange;
// This could be automatically calculated based on the price and priceChange if appropriate
// It could also automatically show the Up or Down indicator
#property (nonatomic, strong, readonly) UITextField *percentChange;
#end
Then, your controller could create an instance and set the various properties:
StockInfo *djia = [[StockInfo alloc] init];
djia.ticker = #"DJIA";
djia.price = #"14550.35" ;
djia.priceChange = #"-111.66";
// ...
You can create the actual UI elements within the view either in Interface Builder, or do it in code. Which to do is kind of a personal preference. There are plusses and minuses to both, and building the view in code in this case would be pretty easy and not require you to have two files in order to use the control.
When I created a UISwitch element in my storyboard, and attached it to the .h file, there was this line generated in the controller:
#property (weak, nonatomic) IBOutlet UISwitch *wantHelp;
And I was trying to figure out how to make the system notice when the value was changed, so I tried to manually add something like this below the original statement:
- (IBAction)wantHelp:(id)helpToggle;
and in the controller, I have something like this:
-(IBAction)helpToggle:(id)sender
{
NSLog(#"sender is: %#", sender);
if (wantHelp.on)
{
NSLog(#"yes");
}
else
{
NSLog(#"No");
}
}
What I wanted to do is connect the helpToggle IBAction with the particular UISwitch element, but when I run it, I get an error: unrecognized selector sent to instance which as I understand is means that I called an operation on an incorrect object.
Could someone help me understand what I am doing wrong here?
Thanks!!
This is how my .m file looks like:
#interface PlanBusinessController ()
#end
#implementation PlanBusinessController
#synthesize businessDescription;
#synthesize personName;
#synthesize personEmail;
#synthesize privacy;
#synthesize wantHelp;
-(IBAction)helpToggle:(id)sender
{
NSLog(#"sender is: %#", sender);
if (wantHelp.on)
{
NSLog(#"yes");
}
else
{
NSLog(#"No");
}
}
What's happening is that your UISwitch has been told to call wantHelp: however as no method called this exists in you implementation file (.m file) that is why the 'unrecognized selector sent to instance' error is being called.
So you can have as many IBAction as you want or one it doesnt matter. What matters most is declaring it in your .h file, going into interface builder and linking the desired action to that IBAction.
so you have your IBAction
-(IBAction)WHATEVERNAME:(id)sender
then go to interface builder and click on your File's Owner object(kinda top left). then click on the Connections Inspector (top right)
and drag from the dot where it says WHATEVERNAME to your object (UISwitch wantHelp)
when you do that it will ask you what action you want to receive
take in mind the reason for (id)sender is that you are suppose to cast your object
UISwitch * tempSwitch = (UISwitch*) sender;
so that you have a pointer to the switch object
this is because you could have this same IBAction method handle many different types of objects
although this is all good stuff the actual error came from multiple selectors being called. Once we got into the connection inspector we were able to see the 2 different methods being called by it. One was the valid IBAction and the other was a previously declared method wantHelp
Okay so all the answers failed to give you "the easy way"
Hold down control on your UISwitch and drag it to your .h file.
You will then see a dialog box which will allow you to select the "Connection"
This connection determines if you are creating and IBOutlet or an IBAction.
Once you change it to "Action" you will then have it automatically select "ValueChanged" as the event, and you can give it whatever name you want:
I named it helpSwitchToggled. Then you will have your IBAction in the .h, and in the .m files.
In your .m file you can then write your code for the value changed action:
for copy paste:
- (IBAction)helpSwitchToggled:(id)sender {
if(self.helpSwitch.on)
{
//Do the On stuff
} else {
//Do the Off Stuff
}
}
That is "The easy way" to make an action associated with something on your interface.
The difference between IBAction and IBOutlet has been pointed out in other answers, but basically Actions are responses to control events and Outlets are connections to elements within the view.
IBAction is merely a tag to let Interface Builder know it can attach to that action.
IBAction is defined as void but with the name Interface Builder allows you to drag your connection over it and connect an event from an object to that function.
Other than that Your actions should have meaningful names. helpToggle seems to me to be an on off switch. but usually I would include a bit of description in that message as well. Such as
- (IBAction) helpSwitchToggled:(id) sender{
}
this message gives you a very meaningful name and reading it will tell you exactally what is calling it as well as the type of message that object is sending.
In conjunction I would also have an IBOutlet for that switch called helpSwitch, Like this one.
#property (nonatomic, weak) IBOutlet UISwitch *helpSwitch;
as you can see. that object is clearly a switch. And IBOutlet is actually defined as nothing. but it again is a tag that Interface Builder uses to know you have a property that can be linked to with Interface Builder.
IBAction and IBOutlet are nothing more than Metadata that tells the Interface builder that this is a possible connection. Connecting them is up to you and the compiler treats them like nothing.
I hope this information helped you :)
When using IB in combination with assistant view you control-drag an element in the IB to the .h file and create an outlet. You can drag it to one of 2 place, either inside the variable declaration block or outside the block.
If you drag it inside the variable block you get something like this:
#interface MyViewController : UIViewController {
IBOutlet UIButton *foo;
}
dragging it outside the block gives you something like....
#interface ViewController : UIViewController {
}
#property (retain, nonatomic) IBOutlet UIButton *foo;
I've thought about how they are different and I'm a little confused. Ok, I understand synthesized properties do some magic and create instance variables at runtime (only on 64bit/ARM). So I believe I understand how the 2 options work.
What's the best option though? First option generates less code and seems simpler.
Second version offers public accessors/mutators, but I rarely access outlets from outside my class (and if I do, it's almost always with encapsulation). From the time I've started iOS work I've exclusively used this option.
Am I missing anything or should I make the switch to variable based outlets in most cases?
The ability to declare IBOutlet in the property declaration is relatively new #property (retain, nonatomic) IBOutlet UIButton *foo;
Previously, you had to declare IBOutlet UIButton *foo inside the curly braces and then synthesize the property. Now, declaring the IBOutlet in the curly braces is redundant.
You have two options to declaring the properties now. Option 1 is to declare it in your .h file, which will make it public. Alternatively, you can create a private interface in your .m file using:
#interface MYCLASS()
#end
and declare your properties there. This is my preferred way of doing it unless I need public access to that property (which should be the exception, not the norm if you are obeying MVC conventions).
Short answer: It doesn't make a much of a difference either way.
Long answer: If you want set/mutator methods, then drag outside of the block. If you don't care about methods and are just going to access the variables directly then putting them in as straight variables inside the block is probably the way to go.
Public visibility:
If you just specify the IBOutlet as a variable then you can use #private or #protected to prevent outside access. If you really want a #property for some reason you can still control public visibility by moving the property out of the .h and into a class extension in the .m file.
Conclusion: Myself, I'm sticking with the straight variable declaration and save the other options for when I need something extra.
IBOutlets are best inside of the block, unless you really plan on working with it in the .m file.
Remember, you can have both. The one inside of the variable block is essentially, in all basics, just for when you use it in IBActions.
The property can be used in the .m file for further customization.
Again, you can use both, it just depends on the extent you're using it.