Super class Resource
#interface Resource : CoderObject
#property (strong, nonatomic) NSString *resourceID;
#property (assign, nonatomic) ResourceType resourceType;
#property (assign, nonatomic) DataType dataType;
#end
Subclass ViewResource
#interface ViewResource : Resource
#property (strong, nonatomic) CustomView *view;
#property (strong, nonatomic) UIViewController *viewController;
#end
In subclass ViewResource's init method how to access Resource's variable dataType? Now I'm trying to just use super.dataType = ...
Is there other ways?
You just need to use self.dataType. Your subclass has full visibility of all of the superclass properties defined in the .h file. Using self.xxx also gives you the ability to override the accessor methods if required in the future without coming back to edit all of your usage code.
Looking at your link below, fair enough. Those are all valid points. Accessors shouldn't have side effects but you can't guarantee they won't. If the property is defined the superclass then you have a couple of options:
Use self.xxx to set the property and endeavour to ensure no side effects
Call an init method on super, passing the required parameters, and set them there
Like Wain stated in his answer you have direct access to your super's class members (if they are not private).
And there is no problem calling self.property in the init method as long as your init looks like this
-(id)initAndTheNameYoWantAndMaybeSomeParameters:(NSString *)paramExample {
self = [super initNameOfAnInitMethodFromSuperClass];
//check if the init was with success
if(self != nil) {
self.myStringProp = paramExample;
//or
self.propertyFromSuper = paramExample;
}
}
Yes, you can also do stupid stuff in the initMethods (I did it before :)) ) like calling the same initMethod from inside it which was generating a recursive calling that was crashing my app. (Easy to spot this issue)
Related
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'm new to objective-c and found some OO features I have learned from other language is different in objective-c. The most confusing question for me until now is how to reimplement a property in subclass, or should I do this?
For example, I have two view controllers GameViewController and CardGameViewController.
#interface GameViewController : UIViewController {
Game *_game;
}
#property (nonatomic) Game *game;
#property (strong, nonatomic) IBOutletCollection(UIButton) NSArray *cardButtons;
#property (weak, nonatomic) IBOutlet UILabel *scoreLabel;
#property (weak, nonatomic) IBOutlet UILabel *messageLabel;
#end
#interface CardGameViewController : GameViewController
#property (nonatomic) CardMatchingGame *game;
#end
CardMatchingGame is derived from Game. #property game in GameViewController is implemented like below:
- (Game *)game
{
if (!_game) {
_game = [[Game alloc] initWithCardCount:[self.cardButtons count]
usingDeck:[self createDeck]];
}
return _game;
}
I tried to reimplement #property game like below but got a warning in the return clause which said Incompatible pointer types returning 'Game *' from a function with result type 'CardMatchingGame *'.
- (CardMatchingGame *)game
{
if (!_game) {
_game = [[CardMatchingGame alloc] initWithCardCount:[self.cardButtons count]
usingDeck:[self createDeck]
matchThreshold:self.threshold.selectedSegmentIndex + 2];
}
return _game;
}
Is this the correct way of reimplementing a property in subclass? If not, what am I supposed to do?
You can't reimplement like that (well, you could do a ton of casting, but that isn't a good option).
One option is to create the property as #property (nonatomic) id game; and then it can hold any type of Game class (or subclass) that you have. And, because it is id type the compiler will assume that any method you try to call is valid. Obviously you could make mistakes which you won't find till later.
Another, better, option is to add a new property in the subclass as #property (nonatomic) CardMatchingGame *cardGame; and, in the subclass, when a new game is created the CardMatchingGame instance is stored in both game and cardGame properties. Now, the superclass has access to game and can use it, and the subclass has access to cardGame, which is typed as the correct class. So, you have compiler checks and usage of the same instance in both classes. But, you haven't reimplemented a property - you have multiple properties, each doing the appropriate task for their location + purpose.
If CardMatchingGame is a subclass of Game you can override - (Game *)game and return your CardMatchingGame object. Just make sure not to change the return type.
I think the problem is ivar in parent class Game *_game; it produce warning you see. Try to use different name or id type for it.
or just cast it before return (CardMatchingGame *)_game;
I'm going through a tutorial on core-data in Objective-C and can't understand the following syntax:
#interface RootViewController : UITableViewController <CLLocationManagerDelegate> {
NSMutableArray *eventsArray;
NSManagedObjectContext *managedObjectContext;
CLLocationManager *locationManager;
UIBarButtonItem *addButton;
}
#property (nonatomic, retain) NSMutableArray *eventsArray;
#property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;
#property (nonatomic, retain) CLLocationManager *locationManager;
#property (nonatomic, retain) UIBarButtonItem *addButton;
#end
We have four properties here that are declared in the implementation file, which to my understanding means they are private. What exactly is happening within the curly brackets? Why are these variables put there? And also, is it a class extension? I see () are missing here so probably it is not. What is this kind of syntax called then?
Its not a category.Its just a class named RootViewController which extends UITableViewController and implements protocol CLLocationManagerDelegate.
Coming to your braces ->
generally if you don't create iVars in curly braces, by default they are created with underscore as prefix to them. This is done by compiler.
But here, you explicitly said, that the ivar should be without underscore(_).
Any you should synthesize them as below or else it will give a warning.
#synthesize eventsArray= eventsArray;
It's just a regular definition of a RootViewController class, the #interface doesn't necessarily have to be in a header file, private classes (that shouldn't/don't need to be accessible elsewhere) can also be defined directly in the .m file.
The definitions in the curly braces are just regular instance variables of the RootViewController class.
What you have is called the class interface. It is just the .h file of your program files. .If you want a class category, just do
#interface RootViewController (CategoryName)
and for an extension, inside the .m type
#interface RootViewController ()
#end
#implementation
Variables between curly braces:
{
NSMutableArray *eventsArray;
NSManagedObjectContext *managedObjectContext;
CLLocationManager *locationManager;
UIBarButtonItem *addButton;
}
are just usual variables.
For variable, defined with #property base word:
#property (nonatomic, retain) NSMutableArray *eventsArray;
#property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;
#property (nonatomic, retain) CLLocationManager *locationManager;
#property (nonatomic, retain) UIBarButtonItem *addButton;
created accessor and mutator methods. And also you can define options for those variables in bracers. Plus you can get local synonym for them, using base word #synthesize in .m file, like
#synthesize addButton = myLovelyButton;
then you can use myLovelyButton in .m file instead addButton
Both of these definition do not belong to the category.
For define category just type code like:
#interface <#className#> (<#categoryName#>)
{
//optional variables here
int i;
NSString *s;
}
//optional variables here
#property NSString *str;
//optional methods here
-(void)doSomething;
#end
Then you can implement your methods and use these variables:
#implementation <#className#> (<#categoryName#>)
-(void)doSomething
{
int i = 0;
str = #"blah";
s = #"wow";
NSLog(#"%i - %# - %#",i,str,s);
}
#end
Use that for add your methods to existing classes.
Variables inside brackets directly after the #interface or #implementation are instance variables. These are variables associated with each instance of your class, and thus accessible anywhere in your instance methods.
If you don't put the brackets, you declare global variables. Any variable declared outside of any bracket block will be a global variable, wether these variables are before or after the #implementation directive. And global variables are evil and needs to be avoided at all costs (you can declare global constants, but avoid global variables), especially because they are not thread-safe (and may thus generate bugs that are a mess to debug).
#interface YourClass : ParentClass
{
// Declare instance variables here
int ivar1;
}
// declare instance and class methods here, as well as properties (which are nothing more than getter/setter instance methods)
-(void)printIVar;
#end
// .m
int someGlobalVariable; // Global variable (bad idea!!)
#implementation YourClass
int someOtherGlobalVariable; // Still a bad idea
-(void)printIVar
{
NSLog(#"ivar = %d", ivar1); // you can access ivar1 because it is an instance variable
// Each instance of YourClass (created using [[YourClass alloc] init] will have its own value for ivar1
}
Only modern compilers let you declare instance variables (still in brackets) also inside either your class extension (#interface YourClass () in your .m implementation file) or in your #implementation, in addition to the possibility to declare them after the #interface in your .h. The benefits being to hide those instance variables from external users of your classes, by declaring them in the .m file and not in the .h file anymore, because users of your class don't need to be aware of the internal coding details of your class, but only needs to know the public API.
One final advice: instead of using instance variables, Apple more and more recommends to use #property directly, and let the compiler (explicitely using the #synthesize directive, or implicity with modern LLVM compilers) generate the internal backing variable. So that at the end you generally won't need to declare instance variables at all, and thus omit the empty { } after the #interface directive:
// .h
#interface YourClass : ParentClass
// Declare methods and properties here
#property(nonatomic, assign) int prop1;
-(void)printProp;
#end
// .m
#implementation YourClass
// #synthesize prop1; // That's even not needed with modern LLVM compiler
-(void)printProp
{
NSLog(#"ivar = %d", self.prop1);
}
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.
I am having a label code for "decisionText" inside dot-m file as follows :
#synthesize decisionText ; //<<<This generates the error
inside dot-h file, the code is written as follows:
IBOutlet UILabel *decisionText
The error i get is :
No declaration of property 'decisionText found in the interface.
ps: In the interface builder when i click the label, i can find the name "decisionText" under Referencing Outlets mapped with File's Owner
Stuck on this. :(
As suggested I removed line #synthsize decisionText and used :
#property (nonatomic,weak) IBOutlet UILabel *decisionText ;
Now i get the error :
Expected a property attribute before 'weak'
Dot M file :
#import "ClickButtonViewController.h"
#implementation ClickButtonViewController;
//#synthesize decisionText ;
#property (weak,nonatomic) IBOutlet UILabel *decisionText ;
-(IBAction)buttonPressed:(id)sender
{
decisionText.text = #"Go for it!" ;
}
-(void)dealloc{
[decisionText release];
[super dealloc] ;
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
#end
in the .h file add:
#interface ViewController : UIViewController
{
//....
IBOutlet UILabel *decisionText ;
//...
}
#property (nonatomic, retain) IBOutlet UILabel *decisionText ;
//...
#end
then in the .m file add:
#synthesize decisionText ;
You use #synthesize statements with declared properties. Thus, your code should probably look like:
#interface ViewController : UIViewController
{
// your ivars go here
// but this is not needed:
//
// IBOutlet UILabel *decisionText;
}
// your properties go here
#property (nonatomic, retain) IBOutlet UILabel *decisionText;
#end
If you're using ARC, replace retain with weak.
And in your .m file, you would have:
#implementation ViewController
#synthesize decisionText = _decisionText;
// and your implementation goes here
Note:
While you can explicitly declare your instance variable, if you omit it, the #synthesize statement will create one for you. Thus, you don't need to explicitly declare any instance variable. In fact, I might argue that you should not explicitly declare your instance variable because if you have a typo, it only presents an opportunity to accidentally end up with two instance variables, the one you explicitly declared and the one the compiler will generate. I've seen that problem here on Stack Overflow more than once. So, in my example, I've omitted the explicit instance variable declaration and I'll let the compiler take care of it for me and it minimizes the chance for error.
While not required, it is often advised that #synthesize statements specify a different name for your property's instance variable (e.g., in this case, I'm suggesting that the property decisionText would have an instance variable of _decisionText). This helps discourage the accidentally reference to instance variables when you meant to invoke the property's getter or setter. (In fact, in Xcode 4.4 and later, if you omit the #synthesize statement, the compiler will automatically synthesize the instance variable for you with the leading underscore.) Thus, in your code, you would then refer to the property self.decisionText or to the instance variable _decisionText. It's generally not so critical for IBOutlet objects, but as you start to use your own custom properties, this convention becomes useful.
Alternatively, if you are using Xcode 4.4 you can use autosynthesis.
In which case you don't need to declare the iVar you can just write:
#property (weak, nonatomic) IBOutlet UILabel *decisionText;
And you don't need to write the #sythesize line at all.
If you do this - be aware that the generared iVar will have a leading underscore appended by default, although you should just stick to using the property accessor in this case so it makes little difference.
You can see what you can do in the Objective-C Features Availability Index
Change
IBOutlet UILabel *decisionText
to
#property (nonatomic, weak) IBOutlet UILabel *decisionText
You can only synthesize properties you defined like that with the #property keyword
You declared only the instance variable which will store the content of your property but you didn't declare the property itself. I think that the easiest way to solve that is to add in your public interface (.h file) or in your private interface (#interface ClassName () ... #end in ClassName.m file) the declaration of the property.
ClassName.h
#interface ClassName : ParentClass
#property (nonatomic, weak) IBOutlet UILabel decisionText; //This is the declaration of the property than you can ctrl-drag to wire it up to your label
#end
ClassName.m
#implementation ClassName
#synthesize decisionText = _decisionText //the _decisionText stuff is the name of the instance variable that will store the content of your property
... //your methods
#end