Are there a differences between these two lines of code?
__weak IBOutlet UITextField *usernameField;
#property (weak) IBOutlet UITextField *usernameField;
What if you declare either of these in interface section of the .h or the .m files?
Yes. The first example declares a weak instance variable called usernameField, but the second declares a weak property called usernameField, and an instance variable called _usernameField that is accessed by the property.
If you declare it in an #interface section of the .m file, then it can only be accessed in that .m file (unless you mess with the Objective-C runtime).
The difference is not in the weak reference but just in the fact that the first is an instance and the second is a #property.
__weak and (weak) is the same thing, but the second is used as attribute for properties.
Related
In Objective-C I'm used to declaring properties that connect to Interface Builder with
#property (nonatomic, weak) IBOutlet UIView *myView;
Now I have a class that uses the new XCode nullability attributes. To preserve compatibility with Swift, what nullability attribute should an IBOutlet have? According to Apple's "Using Swift with Cocoa and Objective-C":
When you declare an outlet in Swift, you should make the type of the outlet an implicitly unwrapped optional. This way, you can let the storyboard connect the outlets at runtime, after initialization. When your class is initialized from a storyboard or xib file, you can assume that the outlet has been connected.
So does this mean the outlet should be declared nonnull in Objective-C?
If your class is written in Swift, you can't use a non optional property because otherwise the compiler is going to complain that the property is never initialized. That's why Apple recommends to declare it as an implicitly unwrapped optional, because once your object has been initialized, you know for sure that the property contains a value (unless you have a dangling outlet, which can happen by the way...)
When exporting from Objective-C, you can mark it as nonnull and it will appear in Swift as a non optional property which is fine in that case. Note that you can't use both nonnull and weak.
So you can either do :
#property (nonatomic, strong, nonnull) IBOutlet UIView *subview;
// Exported to Swift as #IBOutlet var subview: UIView
or
#property (nonatomic, weak, nullable) IBOutlet UIView *subview;
// Exported to Swift as #IBOutlet weak var subview: UIView?
If for some reason you still want the property to be exported to Swift as an implicitly unwrapped optional, you can mark the property as null_resettable or null_unspecified. That's not really what they are meant for but it will still produce the desired result. See this blog post for more on these annotations.
#property (nonatomic, weak, null_unspecified) IBOutlet UIView *subview;
// Exported to Swift as #IBOutlet weak var subview: UIView!
The declaration of weak implies that the property is nullable. Therefore this works
#property (nonatomic, weak, nullable) IBOutlet UIView *contentView;
Declaring the property nonnull gives an error.
As I read in another question, a rule of thumb was:
When a parent has a reference to a child object, you should use a strong reference. When a child has a reference to its parent object, you should use a weak reference or a unsafe_unretained one (if the former is not available). A typical scenario is when you deal with delegates. For example, a UITableViewDelegate doesn't retain a controller class that contains a table view.
Well, in this case I have a view controller with a table view IBOutlet. This table view also uses the view controller as a delegate and data source. By the rule above, the view controller acts as the parent and so I should have a strong reference to the table view - the table view should have a weak reference to the view controller.
I'm not sure how to define that latter weak reference - I'm setting
tableView.delegate = self;
tableView.dataSource = self;
How am I supposed to make myself weak? Or is this not the right way to do it?
You can just drag the outlet from your UITableView to your .h file. Xcode will create appropriate property for you. You can choose weak/strong type from there as well while naming the Outlet.
If you would however like to create it manually, you can add this line to your .h file:
#property (weak, nonatomic) IBOutlet UITableView *tblView;
But do keep in mind that even after adding this line to your .h. file, you will still have to connect it to your UITableView.
Also don't forget to make your ViewController conform to UITableViewDelegate like below:
#interface MyTableViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
In your title however, you seem to be confused about the difference between Weak and Strong properties. Ole Begemann has answered about the difference splendidly on This question.
The code you wrote is fine. You don't have to make yourself weak. The delegate and datasource properties are declare as weak in the UITableView definition.
delegate and datasource are already weak as per UITableView.h.
#property (nonatomic, weak, nullable) id <UITableViewDataSource> dataSource;
#property (nonatomic, weak, nullable) id <UITableViewDelegate> delegate;
If any instance is set as delegate and datasource won't get retained by tableview instance
And when you make a IBOutlet make it like this. Choose weak if its strong by default its weak as shown in image
#property (weak, nonatomic) IBOutlet UITableView *tableview;
As the view is already retained by the view it's added (i.e self.view)
It is just like a view in UIKit Control to display data in list form. It is not a child controller. All UIKit items are referenced as weak.
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
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.
While creating a custom iOS table view cell, I created a new .xib file, dragged/dropped some UI elements in interface builder and my .h file looked like this...
#import <UIKit/UIKit.h>
#interface MasterTableViewCell : UITableViewCell
{
IBOutlet UILabel *cellLabel;
IBOutlet UIImage *cellImage;
}
#property (nonatomic, retain) IBOutlet UILabel *cellLabel;
#property (nonatomic, retain) IBOutlet UIImage *cellImage;
#end
On some blogs I saw that the instance variables were missing. When do I need to declare instance variables? Are both instance variables and #property declarations not needed for a particular UI object.
Also I am creating the app using automatic reference counting, so garbage collection needs aren't there as well. What difference does that make in usage of instance variables & properties?
There is no garbage collection in iOS. iOS uses reference counting to track ownership of objects. Using ARC does not do away with reference counting, but the compiler takes care of releasing and retaining objects. When using ARC you are not allowed to send a retain, release, or autorelease message to an object, nor are you allowed to call [super dealloc] in a dealloc method. In your code above, since you are using ARC, the 'retain' attributes should be replaced by the 'strong' attribute.
When you use #property, and the corresponding #synthesize in your implementation, you do not need to create a backing instance variable - the compiler does that for you. #property along with #synthesize create your accessor methods (your getters and setters), and also enable you to use dot notation to refer to your objects' properties. You may still write your own accessor methods if you choose.
The above code could be replaced by the following:
#import <UIKit/UIKit.h>
#interface MasterTableViewCell : UITableViewCell
#property (nonatomic, strong) IBOutlet UILabel *cellLabel;
#property (nonatomic, strong) IBOutlet UIImage *cellImage;
#end
In your implementation file you would have:
#import "MasterTableViewCell.h"
#implementation MasterTableViewCell
#synthesize cellLabel;
#synthesize cellImage;
or
#synthesize cellLabel, cellImage;
... remainder of your code
In your code, to ensure that you are using your accessor methods, use 'self' to refer to your properties:
self.cellLabel.text = #"some text";
or
[[self cellLabel] setText:#"some text"];
I hope this helps clarify things a little.
If you don't create the instance variables (iVar's) then they will automatically be created for you if you are using the #synthesize directive (see below) so they really aren't required. If you are using #dynamic or writing your own methods and want to access the iVar directly then you need to declare it yourself.
In the documentation for Declared Properties under the Property Implementation Directives section, it states:
#synthesize You use the #synthesize directive to tell the compiler
that it should synthesize the setter and/or getter methods for a
property if you do not supply them within the #implementation block.
The #synthesize directive also synthesizes an appropriate instance
variable if it is not otherwise declared.
Note that this behavior is for "modern" runtimes (2.0 and newer). Before this, the iVar was required to be declared or the #synthesize would generate an error.