This question already has answers here:
Objective-C: Property / instance variable in category
(6 answers)
Closed 9 years ago.
I'm trying to create NSString Category but the app crashes when trying to access getters/setters.
#import <Foundation/Foundation.h>
#import <AddressBook/AddressBook.h>
#interface NSString (MyCat)
#property (assign, nonatomic) ABRecordRef personRef;
- (void)setPersonRef:(ABRecordRef)personRef;
- (ABRecordRef)personRef;
#end
Can anyone point out the problem?
You cannot add properties to a class via a category. Adding methods is allowed because it doesn't increase the size of the class. Properties don't just add a getter and setter method, they also add a field to your class. The best way to add properties/fields to an existing class is to subclass it.
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).
This question already has answers here:
What are the default attributes for Objective-C properties?
(3 answers)
Closed 7 years ago.
A #property can be set as strong, weak , assign , copy ... like
#property (copy, nonatomic) NSString *string;
#property (strong ,nonatomic) CustomClass *object;
#property (weak,nonatomic) id <CustomDelegate>delegate;
However, if
#property id <CustomDelegate>delegate; weak?strong?
#property (copy, nonatomic) NSString *string; strong?
If (weak,nonatomic) is abbreviated. What is the default value of an id? And other?
Properties Are Atomic by Default
This means that the synthesized accessors ensure that a value is always fully retrieved by the getter method or fully set via the setter method, even if the accessors are called simultaneously from different threads.
Because the internal implementation and synchronization of atomic accessor methods is private, it’s not possible to combine a synthesized accessor with an accessor method that you implement yourself. You’ll get a compiler warning if you try, for example, to provide a custom setter for an atomic, readwrite property but leave the compiler to synthesize the getter.
For more detail you can read this article https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/EncapsulatingData/EncapsulatingData.html
Thanks
id is a reference to some random Objective-C object of unknown class, thus it's default attributes are:
#property (atomic, readwrite, strong) id value;
Note: delegates 99.999% of the time should be weak.
This question already has answers here:
How does an underscore in front of a variable in a cocoa objective-c class work?
(9 answers)
Why rename synthesized properties in iOS with leading underscores? [duplicate]
(4 answers)
Closed 8 years ago.
I'm following along with a Lynda.com OCUnit testing tutorial that uses XCode 4. In one of the demos, it synthesizes properties in a Location.m file like this
#import "Location.h"
#implementation Location
#synthesize locationManager=locationManager_;
#synthesize speed=speed_;
The properties have a trailing underscore. In other tutorials I've followed (such as the Stanford iOS class), the synthesized properties usually are prefixed with an underscore for the instance variables.
When the properties are created in the .h file, there are no underscores.
#property (nonatomic, strong) CLLocationManager *locationManager;
#property float speed;
Why the trailing underscore in the synthesize statement?
By writing
#synthesize locationManager=locationManager_;
you are defining an ivar locationManager_which backs up your property.
So, to the property you still refer using
self.locationManager
However, ivar, "behind" that property is now called: locationManager_
#synthesize allows you to specify the name of the ivar. The property is named locationManager but the ivar is named locationManager_.
This question already has answers here:
Objective-C ARC: strong vs retain and weak vs assign
(8 answers)
Closed 9 years ago.
#property (nonatomic, strong) NSString *dude;
#property (nonatomic) NSString *dude;
#property (nonatomic, weak) NSString *dude;
What exactly is the difference between these 3?
There's no difference between the first and second, as "strong" is the default & implicit attribute.
The third uses a weak reference, which means that when the object is released by the last owner, the dude property becomes nil.
Oh, lastly, NSString properties should actually be declared with "NSString *".
I'm subclassing a UIToolbar because I'm gonna reuse it all over my app. The UIToolbar uses a delegate protocol:
//
// UIToolbarCustom.h
//
#import <UIKit/UIKit.h>
#protocol UIToolbarCustomDelegate
#required
- (void)tab:(UIBarButtonItem *)sender;
- (void)ok:(UIBarButtonItem *)sender;
#end
#interface UIToolbarCustom : UIToolbar {
id <UIToolbarCustomDelegate> delegate;
}
#property (strong, nonatomic) id delegate;
#end
The standford iOS development course teacher recommends to explicit declare all the ivars prefixing it with a underscore, like:
#implementation UIToolbarCustom
#synthesize delegate = _delegate;
#end
But, in this specify scenarion it gives me a error:
error: property 'delegate' attempting to use ivar '_delegate'...
The code works just fine if I use:
#synthesize delegate = __delegate; or
#synthesize delegate;
What is going on here? Is there a private instance variable in the UIToolbar class named _delegate?
UPDATE
Thank all you guys for all the clarifications and protips, I'm learning a lot. Turns out that I'm new to iOS development (this is my first app second version, so I'm trying to do it right =p). Following the tips I came out with this new header file:
//
// Toolbar.h
//
#import <UIKit/UIKit.h>
#protocol ToolbarDelegate
#required
- (void)tab:(UIBarButtonItem *)sender;
- (void)ok:(UIBarButtonItem *)sender;
#end
#interface Toolbar : UIToolbar
#property (strong, nonatomic) id delegate;
#end
Notes:
The class prefix was removed.
The delegate declaration was removed (I'm using a ios delegate tutorial code, but the code sample uses a older xcode version, where the declaration is needed).
The synthesize was removed, I also didn't knew that we don't need synthesize our properties anymore.
PS: Obviously the code does not work, because the ivar problem. I'm gonna change its names, so I don't need to synthesize it, not sure about what name to use anyways...
What is going on here? Is there a private instance variable in the UIToolbar class named _delegate?
Yes, that's exactly the problem. You need to come up with a different name for your instance variable. __delegate will work, or you could prefix the name with a 3 letter prefix (see last paragraph).
Do note that you've declared your ivar as delegate, then in the synthesize statement told the compiler to use _delegate. Effectively that means that your delegate ivar isn't being used at all. In any case, if you're writing for iOS (as opposed to 32-bit Mac), like you are, you don't need the explicit instance variable declaration in your subclass's #interface section, because the compiler will automatically create it for you.
Finally, it's bad form to name your own subclass something that begins with 'UI', since the UI prefix is reserved for classes that are part of UIKit. You should use your own 3 letter prefix instead, or else no prefix at all. The problem is that a future version of UIKit could conceivably include a class called "UIToolbarCustom", and your subclass would collide with it.
Since last year, when Xcode 4.3 came out, you don't need to synthesize your properties. It is done for you by the compiler (an ivar is generated, and a leading underscore is added to its name). This means that you also don't need to declare an ivar. If you do, be sure to name it something other than _delegate.
So, all you really need is this line:
#property (strong, nonatomic) id<UIToolbarCustomDelegate> delegate;
UPDATE: please see the Andrew Madsen's answer for the full story. Turns out UIToolbar has its own ivar named _delegate. Who knew!