Just when you think you understand something, you don't! :)
I understand that if I make a variable a property, I can access it anywhere in the Class and even set it from outside that class.
I thought if I didnt need it I could just make it an ivar. So I have a viewcontroller with about 5 UILabels. So in its viewDidLoad I say:
pharmacyName.text = self.receivedLocation.name;
pharmacyTel1.text = #"556-7843";
pharmacyTel2.text = #"991-2345";
pharmacyTel3.text = #"800-0001";
When I have declared them like so in the .h file:
#interface DetailViewController : UIViewController{
IBOutlet UILabel *pharmacyName;
IBOutlet UILabel *pharmacyTel1;
IBOutlet UILabel *pharmacyTel2;
IBOutlet UILabel *pharmacyTel3;
}
#property (nonatomic,strong) MyLocation *receivedLocation;
#end
No. Its not mandatory to create ivar as property. If you don't want to access it outside of class just use as it is. In ARC you can also declare your IBOutlet as below:
#interface DetailViewController : UIViewController{
__weak IBOutlet UILabel *pharmacyName;
__weak IBOutlet UILabel *pharmacyTel1;
__weak IBOutlet UILabel *pharmacyTel2;
__weak IBOutlet UILabel *pharmacyTel3;
}
This will keep a week reference of outlets. Here is detail of __weak and strong
There are always many ways you can approach programming tasks and standards. Our group has started using a few coding standards. We like to put our instance variables that are NOT accessed from outside the class (and protocol statements) in the private interface in the .m file like this:
#interface DetailViewController() {
NSString *value_;
}
#end
We also like to use #property for our instance ivars and declare those in the private interface as well like this:
#interface DetailViewController() {
}
#property (nonatomic, strong) IBOutlet UIlabel *pharmacyName;
#end
and then in your code, you would refer to this as self.pharmacyName. It seems to work pretty well with autocomplete, and with getting and setting. Also when you have thread safety issues, the nonatomic, strong behavior comes in handy.
Related
Why is this code okay?
#interface AddViewController : UIViewController <UIPickerViewDelegate>
{
IBOutlet UILabel *category;
IBOutlet UIPickerView *categoryPicker;
}
#end
But this code is not
#interface AddViewController : UIViewController <UIPickerViewDelegate>
IBOutlet UILabel *category;
IBOutlet UIPickerView *categoryPicker;
#end
Also, I was looking up a video on how to use the UIPickerView, and instead of making properties for the IBOutlet, he just made the outlets. Which clearly has something to do with why those curly braces are there.
category and categoryPicker are instance variables, not properties. You either reference them directly via their name e.g. category or by using self->category.
Instance variables are declared in the curly braces, while properties are declared with #property
Instance variables do not have setter and getter methods, while properties have.
you need to change "IBOutlet UILabel *category;" to "#property (nonatomic, strong) IBOutlet UILabel *category;", the same for "IBOutlet UIPickerView *categoryPicker;"
Within the bracket {}, category and categoryPicker are instance variables, but if you delete the "{}", you need to use "property" so that they work the same way
I'm developing for iOS 7 but I still have to manually write getters otherwise my properties just don't get initialized. I tried to manually synthesize those properties, even though that shouldn't be needed anymore, but that doesn't do it.
In my view controller below, I use the property motionTracker, which never gets initialized. I have the same issue with all my projects, so I know it's a misunderstanding on my part.
#import "ViewController.h"
#import "TracksMotion.h"
#interface ViewController ()
#property (weak, nonatomic) IBOutlet UIButton *startRecording;
#property (weak, nonatomic) IBOutlet UIButton *stopRecording;
#property (strong, nonatomic) TracksMotion *motionTracker;
#end
#implementation ViewController
#synthesize motionTracker = _motionTracker;
- (void)startMyMotionDetect
{
[self.motionTracker startsTrackingMotion];
}
#end
The motionTracker has a public API for the method startsTrackingMotion so I don't know why this doesn't work.
#import <Foundation/Foundation.h>
#import <CoreMotion/CoreMotion.h>
#interface TracksMotion : NSObject
- (void)startsTrackingMotion;
- (void)stopTrackingMotion;
#property (strong, nonatomic) CMMotionManager *motionManager;
#end
Properties / instance variables are not magically initialized for you. When you say:
#property (strong, nonatomic) TracksMotion *motionTracker;
... you are just reserving memory space for an instance variable (and generating a getter and a setter method through #synthesize or autosynthesis). There is no actual TracksMotion object there until you put one there. You must write code to do that. You must create or obtain a TracksMotion instance and assign it to self.motionTracker at some point, presumably early in the life of self (in this case, that's a ViewController instance). Until you run code that does that, self.motionTracker is nil.
(It is possible that you are being confused because it looks like outlets are automatically initialized. For example, you've got #property (weak, nonatomic) IBOutlet UIButton *startRecording; And sure enough, self.startRecording is a button. But that's because the nib-loading process does for you the very thing I'm saying you must do: it makes a button from the storyboard or .xib file, and assigns it to this instance variable.)
I have Class A which contains a xib with some buttons and a UITextField and Class B which contains a tableView
I want to add Class A to the table view header.
I am importing the xib from class A into class B using [[[NSBundle mainBundle] loadNibName: owner:self options:nil] objectAtIndex:0];
I just want to reflect the button and textview actions inside classB. In ClassB I do have some UITextfield Delegate methods which i expect to be called when typing some text in uitextfield defined and declared in ClassA (xib + property definition in .h file).
Class A .h:
//properties are set from xib file ClassA.xib
#interface ClassA : UIView
#property (unsafe_unretained, nonatomic) IBOutlet UIButton *addC;
#property(strong, nonatomic) IBOutlet UITextField *nText;
#end
Class B.h
#import "ClassA"
#interface ClassB : UIViewController <UITextFieldDelegate, UITableViewDataSource,...>
#property (strong, nonatomic) IBOutlet UITableView *mTableView; //property set from ClassB.xib
#property(strong, nonatomic) IBOutlet UITextField *nText_B;
#property (unsafe_unretained, nonatomic) IBOutlet UIButton *addC_B;
- (IBAction)addC:(UIButton *)sender;
#end
I don't know how to make the link ClassB button and textfield to ClassA
In ClassB viewDidLoad method i;ve tried this:
getHeader = [[ClassA alloc]init];
_addC_B = [getHeader addC];
_nText_B = [getHeader nText];
_nText_B.delegate =self;
_nText_B.text=#"";
but it's not working
I am new to iOS on this side area.
Thank you for your help
You haven't explained your problem well. Classes do not "contain xibs".
If your objective is to create a piece of user interface in XIB and reuse it, you can achieve this with [NSBundle loadNibNamed:owner:options:]. The best way to reference parts of it is through properties like Noval explained in his answer. Another possibility is to attach views to "File's Owner" outlet's properties.
you can't connecting IBOutlet that placed outside your XIB class. but if you just want to access the outlet from other class, it's possible by creating instance of ClassA in ClassB. and then accessing the property like instanceOfClassA.outletObject
What is the technical difference between them and which is the method recommended by Apple?
// 1
#interface CocoaQuizViewController : UIViewController
{
IBOutlet UILabel *myLabel;
}
#end
// 2
#interface CocoaQuizViewController : UIViewController
{
IBOutlet UILabel *myLabel;
}
#property (nonatomic, retain) IBOutlet UILabel *myLabel;
#end
// 3
#interface CocoaQuizViewController : UIViewController
{
UILabel *myLabel;
}
#property (nonatomic, retain) IBOutlet UILabel *myLabel;
#end
// 4
#interface CocoaQuizViewController : UIViewController
#property (nonatomic, retain) IBOutlet UILabel *myLabel;
#end
The default is (generated automatically if you drag and drop outlet directly from xib to source class):
#interface CocoaQuizViewController : UIViewController
#property (nonatomic, weak) IBOutlet UILabel *myLabel;
#end
All are quite OK.
With new LLVM you are supposed to do 4th one.
#interface CocoaQuizViewController : UIViewController
#property (nonatomic, retain) IBOutlet UILabel *myLabel;
//even you use strong and weak intead of retain,assign,copy
#end
In earlier days, you were doing 1, 2 and 3. Now most of the thing is atomatcally done by the compiler. So your work is now easier than never before.
With New Compiler which comes with XCode4.4 and onwards gives you auto-synthesize for all the properties you declare. ivars also get created prefixed with your property name.
The 4th one, Because Now Apple has recommended all developers to make use of properties.
A couple of thoughts:
Your fourth example avoids a whole category of possible bugs that can plague the first three examples, where you can accidentally end up with two ivars (e.g. if you omitted the #synthesize, the compiler would generate an ivar called _myLabel, your myLabel ivar wouldn't be used, and, thus, would end up being redundant and only serve as a possible source of confusion).
If you use ARC (which I'd encourage, if you can), then clearly that retain reference becomes weak.
You probably shouldn't be "writing" the IBOutlet code yourself anyway. It's just an opportunity to introduce a bug. In IB, click on the "assistant editor" to show your code while working on IB, and then control-drag (or right-click-drag) from the control to the code, and IB will write your code for you! See https://stackoverflow.com/a/15551101/1271826 for screen snapshots.
I have a view controller alertForNeedsClassification as a property in another class, as such:
#interface SCAAppDelegate()
{
HomeScreenViewController * _homeScreenViewController;
NSInteger SCAStatus;
}
#property (strong, nonatomic) PromptClassifyViewController * alertForNeedsClassification;
#end
#implementation SCAAppDelegate
#synthesize alertForNeedsClassification;
#synthesize window = _window;
PromptClassifyViewController's interface looks like this:
#interface PromptClassifyViewController : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *headerTitle;
#property (weak, nonatomic) IBOutlet UITextView *message;
#property (weak, nonatomic) IBOutlet UIButton *notNowButton;
#property (weak, nonatomic) IBOutlet UIButton *classifyButton;
#property (weak, nonatomic) IBOutlet UIImageView *backgroundImageView;
#property (weak, nonatomic) IBOutlet UIView *alertView;
#property NSUInteger tag;
#property (weak, nonatomic) IBOutlet id<PromptClassifyViewControllerDelegate> delegate;
- (void)show;
- (void)showFromView:(UIView *)view;
- (IBAction)show:(id)sender;
- (IBAction)dismiss:(id)sender;
- (IBAction)buttonWasPressed:(id)sender;
- (void)setHeaderTitleWithText:(NSString *)text;
#end
I am trying to change the values of IBOutlets message and headerTitle text, like this:
alertForNeedsClassification = [[PromptClassifyViewController alloc] initWithNibName:#"PromptClassifyViewController" bundle:nil];
//[alertForNeedsClassification setDelegate:self];
self.alertForNeedsClassification.headerTitle.text = #"A title";
alertForNeedsClassification.message.text = #"A message";
Then I show alertForNeedsClassification calling a show method (it's like a custom uialertview, but it doesn't subclass from uialertview).
Thing is, no matter how I change it, the text on alertForNeedsClassification.view is always that which is defined in the nib, ie. I can't change it programmatically.
My custom alert view is based on Jeff LaMarche's design: http://iphonedevelopment.blogspot.com/2010/05/custom-alert-views.html
Any ideas what might be going on?
Please be careful when you allocate and initialize the UIView object, especially if you trying to mix using Nib and dynamically generating objects. The best place is within -(void)awakeFromNib or -(void)viewDidLoad
Also, make sure these methods are called. By using -(id)initWithNibName:bundle: only cannot make sure your view to be loaded. Try -(void)addChildViewController and -(void)addSubview: on parentViewController's view to make sure view is loaded after being initialized.
If the text had to be prepared before being loaded, assign it to separate NSString property within PromptClassifyViewController class. Since this property is independent from view being loaded, you can change it's value BEFORE view is appeared. Make sure this text is used and applied to the headerTitle within -(void)show method.
Since you allocate PromptClassifyViewController and access weak referenced headerTitle from self. alertForNeedsClassification, make sure it's not deallocated right afterward.
Usually, weak option is not used for IBOutlet properties. Though it is used when generating outlet connection code by dragging objects from Interface Builder. Try testing your code using strong.
I was assigning values to the IBOutlets before they were alloc'd/initialized. The solution I implemented was to set the values I needed to non-IBOutlet properties (NSStrings in this case) and assign those where needed, in Prompt...Controller's viewDidLoad;