I have two classes:
Base class is player it has property name
Sub class is computer
How can I set the name of the computer player by accessing the base class property?
base class
#interface Player : NSObject
#property (nonatomic) NSString* playerName;
#property (nonatomic) int score;
-(id) initWithName :(NSString*) playerName;
-(void) addScore:(int) points;
#end
subclass
#interface Computer : Player
#end
.m
#import "Computer.h"
#implementation Computer
-(id)initWithName:(NSString *)name{
self = [super init];
}
#end
Your question is difficult to make out so please let me know if I've answered something other than what you are asking.
Assuming you have a class, car, that has inherited from a super class, vehicle, and that vehicle has an attribute, wheels, you can get at that in this way:
super.wheels = 4;
Call the property in the Computer Class like
super.name = #"Bob";
You can also call the methods of the superClass with
super.myMethod();
You can access the property from the superclass in the subclass directly.
Player.h
#interface Player : NSObject
#property(nonatomic, copy) NSString *name;
- (instancetype)initWithName:(NSString *)name;
#end
Computer.h
#interface Computer : Player
#end
Computer.m
#implementation Computer
- (instancetype)initWithName:(NSString *)name {
self = [super initWithName:name];
if (self) {
self.name = #"test";
}
return self;
}
#end
Although, as #Phillip Mills suggested, it's probably better practice to set the name property in Player.m instead.
Related
I want to inherit my base class properties and methods which will be used by my several derived classes. I want these properties and methods to be exactly protected so that they will only be visible in derived class and not to any external class. But it always gives me some errors.
#interface BasePerson : NSObject
#end
#interface BasePerson ()
#property (nonatomic, strong) NSMutableArray<Person*>* savedPersons;
#property (nonatomic) BOOL shouldSavePerson;
#end
#interface DerivedPerson1 : BasePerson
#end
#implementation DerivedPerson1
- (instancetype)init
{
if (self = [super init]) {
self.savedPersons = [NSMutableArray array];
self.shouldSavePerson = NO;
}
return self;
}
It always gives me an error that
Property 'savedPersons' not found on object of type 'DerivedPerson1 *'
Property 'shouldSavePerson' not found on object of type 'DerivedPerson1 *'
How i can make use of inheritance in Objective C, I don't want savedPersons and shouldSavePerson properties to be visible to external classes. I only want them to visible in my base class and all the derived classes.
Any help will be great. Thanks
This is not something that the objectiveC really support. There are some ways though. So lets see.
If you put a property in the source file class extension then it is not exposed and you can not access it in the subclass either.
One way is to put all of the subclasses into the same source file as the base class. This is not a good solution at all as you do want to have separate files for separate classes.
It seems logical to import the BaseClass.m in the SubClass source file but that will produce a linker error saying that you have duplicate symbols.
And the solution:
Separate the extension into a separate header. So you have a MyClass
Header:
#import <Foundation/Foundation.h>
#interface MyClass : NSObject
#end
Source:
#import "MyClass.h"
#import "MyClassProtected.h"
#implementation MyClass
- (void)foo {
self.someProperty = #"Some text from base class";
}
#end
Then you create another header file (only the header) MyClassProtected.h which has the following:
#import "MyClass.h"
#interface MyClass ()
#property (nonatomic, strong) NSString *someProperty;
#end
And the subclass MyClassSubclass
Header:
#import "MyClass.h"
#interface MyClassSubclass : MyClass
#end
And the source:
#import "MyClassSubclass.h"
#import "MyClassProtected.h"
#implementation MyClassSubclass
- (void)foo {
self.someProperty = #"We can set it here as well";
}
#end
So now if the user MyClassSubclass he will not have the access to the protected property which is essentially what you want. But the downside is the user may still import MyClassProtected.h after which he will have the access to the property.
Objective-C doesn't have member access control for methods, but you can emulate it using header files.
BasePerson.h
#interface BasePerson : NSObject
#property (strong,nonatomic) SomeClass *somePublicProperty;
-(void) somePublicMethod;
#end
BasePerson-Private.h
#import "BasePerson.h"
#interface BasePerson ()
#property (nonatomic, strong) NSMutableArray<Person*>* savedPersons;
#property (nonatomic) BOOL shouldSavePerson;
#end
BasePerson.m
#import "BasePerson-Private.h"
...
DerivedPerson1.h
#import "BasePerson-Private.h"
#inteface DerivedPerson1 : BasePerson
...
#end
Now any class that #imports BasePerson.h will only see the public methods. As I said though, this is only emulating access control since if a class #imports *BasePerson-Private.h" they will see the private members; this is just how C/Objective-C is.
We can achieve using #protected access specifier
#interface BasePerson : NSObject {
#protected NSMutableArray *savedPersons;
#protected BOOL shouldSavePerson;
}
DerivedPerson1.m
#implementation DerivedPerson1
- (instancetype)init
{
if (self = [super init]) {
self->savedPersons = [NSMutableArray array];
self->shouldSavePerson = NO;
}
return self;
}
#end
OtherClass.m
#import "OtherClass.h"
#import "BasePerson.h"
#implementation OtherClass
- (void)awakeFromNib {
BasePerson *base = [[BasePerson alloc]init];
base->savedPersons = #[];//Getting Error. Because it is not a subclass.
}
#end
I am practicing inheritance in Objective-C and this is my Person parent class
// This is Person.h
#interface Person : NSObject
#property(nonatomic, strong) NSNumber *age;
#property(nonatomic, strong) NSString *race;
-(instancetype)init;
-(instancetype)initWithAge:(NSNumber*)age andRace:(NSString*)race;
#end
This is what I'm trying to do in my Student class
// This is Student.h
#import "Person.h"
#interface Student : Person
#property(nonatomic, strong) NSString *classification;
#property(nonatomic, strong) NSString *major;
#end
And
// This is Student.m
#import "Student.h"
#import "Person.h"
#implementation Student
-(instancetype)init
{
return [self initWithClassification:#"Freshman" andMajor:#"Computer Science"
andAge:[[NSNumber alloc] initWithInt:20] andRace:#"Caucasian"];
}
-(instancetype)initWithClassification:(NSString*)classification andMajor:(NSString*)major
andAge:(NSNumber*)age andRace:(NSString*)race
{
self = [super init];
if (self)
{
_classification = classification;
_major = major;
_age = age;
_race = race;
}
return self;
}
#end
The compiler is not liking my doing
_age = age;
_race = race;
Use of undeclared identifier _age did you mean age? Can someone tell me where I went wrong? Thank you.
When you declare a property like that, clang will automatically #synthesize it for you (i.e it will create a getter and setter), but synthesized properties are not visible to subclasses, you have different alternatives to make it working.
You can synthesize the ivar in the interface of the subclass
#synthesize age = _age;
Or you can declare the ivar protected on the interface of the superclass, so that will be visible on the subclasses.
#interface Person : NSObject {
#protected NSNumber *_age;
}
Or you can use self.age = ... on your subclass, without using the ivar at all.
Since clang compiler now auto-synthesise properties you don't have, in most cases, to synthesise your properties.
Objective-C Autosynthesis of Properties
Clang provides support for autosynthesis of declared properties. Using
this feature, clang provides default synthesis of those properties not
declared #dynamic and not having user provided backing getter and
setter methods. __has_feature(objc_default_synthesize_properties)
checks for availability of this feature in version of clang being
used.
But in some cases (some examples are in this question) you should explicitly synthesise them.
In this case, to solve your problems you should just add:
#synthesize age = _age;
#synthesize race = _race;
to your code, and you'll be fine.
The subclass has access to the property, but not the backing variable. So you should set it with
self.age = age;
I have four classes MainVC, ParentClient and ChildClient1, ChildClient2(which are subclasses of ParentClient). ParentClient has a delegate to MainVC such that in MainVC
- (void)viewDidLoad
{
[super viewDidLoad];
[ParentClient instance].mainViewDelegate = self;
}
And then the ParentClient looks like this
#interface BaseClient : NSObject
#property (assign) id<MainVCInteraction> mainViewDelegate;
+(instancetype) instance;
#end
Now I want to access mainViewDelegate from ChildClient1, ChildClient2 and it returns me nil while [ParentClient instance].mainViewDelegate returns the correct value
Here is what I did I removed the BaseClient Class so that ChildClient1, ChildClient2 were no longer subclasses of BaseClient. I defined a objective-c protocol file MainVCInteaction.h and made Client1, Client2 look like this:
#import "MainVCInteraction.h"
#interface ChildClient1 : NSObject
#property (assign) id<MainVCInteraction> mainViewDelegate;
+(instancetype) instance;
#end
#import "MainVCInteraction.h"
#interface ChildClient2 : NSObject
#property (assign) id<MainVCInteraction> mainViewDelegate;
+(instancetype) instance;
#end
And then MainVC implements this protocol, I assigned the delegate like this
- (void)viewDidLoad
{
[super viewDidLoad];
[ChildClient1 instance].mainViewDelegate = self;
[ChildClient2 instance].mainViewDelegate = self;
}
Is there any Objective C magic I can use to do the following:
Say I have a Class Foo, with two properties myObj A and otherObj B.
Now...
In the Class implementation file (.m) of myObj (A) I want to access
it's "sibling" property "otherObj B" in the "parent" Class Foo.
Is there something similar to this in objective C to help access sibling properties:
self.ParentClass.b; ?
or
self.OwningClass.b; ?
I know convention is probably to pass a refence to B during init of A, but I don't want to have to create many custom initalisers
Just wondered if there was a shortcut.
#interface Foo : NSObject
#property A
#property B
#end
#interface A : NSObject
#property B
#end
#implementation A : NSObject
self.B = self.parent.B;
#end
Thanks,
If you have
#interface A : NSObject
#property A
#end
#interface B : NSObject
#property B
#end
then A has no way to know B and vice versa. As you said: you have to pass a reference
IF you ever only have ONE instance of A and ONE instance of B then you COULD use a singleton pattern. But it introduces extra dependencies and makes the code less reusable. so while it might work, thats not a way I would recommend.
There's no built in "parent" or "owner" concept (large because the object could, theoretically, have strong references to it maintained from multiple objects). But just add your own parent property:
Thus, consider:
#interface Foo : NSObject
#property (nonatomic, strong) A *a;
#property (nonatomic, strong) B *b;
#end
#interface A : NSObject
#property (nonatomic, weak) Foo *parent;
- (id)initWithParent:(Foo *)foo;
#end
#interface B : NSObject
#property (nonatomic, weak) Foo *parent;
- (id)initWithParent:(Foo *)foo;
#end
So, Foo will own instances of A and B objects (thus the strong references), and A and B will maintain a weak reference to their parent. Note, the weak reference to the parent is critical, to avoid strong reference cycles (a.k.a. retain cycles).
The implementations of these classes might look like:
#implementation Foo
- (id)init
{
self = [super init];
if (self) {
_a = [[A alloc] initWithParent:self];
_b = [[B alloc] initWithParent:self];
}
return self;
}
#end
#implementation A
- (id)initWithParent:(Foo *)foo
{
self = [super init];
if (self) {
_parent = foo;
}
return self;
}
- (void)someRandomMethod
{
B *sibling = self.parent.b;
// now do whatever you want with your reference to the sibling object
}
#end
#implementation B
- (id)initWithParent:(Foo *)foo
{
self = [super init];
if (self) {
_parent = foo;
}
return self;
}
#end
Notice, in A I have a someRandomMethod which illustrates how it could get access to its sibling, B. You could do the same thing from B to A, too.
I know you say you don't want to have to write your own custom init methods, but that's the right way to do it. Or just call the default init method and manually set the parent property of the child objects, e.g.:
_a = [[A alloc] init];
_a.parent = self;
_b = [[B alloc] init];
_b.parent = self;
I want to override an NSString property declared in a superclass. When I try to do it using the default ivar, which uses the the same name as the property but with an underscore, it's not recognised as a variable name. It looks something like this...
The interface of the superclass(I don't implement the getter or setter in this class):
//Animal.h
#interface Animal : NSObject
#property (strong, nonatomic) NSString *species;
#end
The implementation in the subclass:
//Human.m
#implementation
- (NSString *)species
{
//This is what I want to work but it doesn't and I don't know why
if(!_species) _species = #"Homo sapiens";
return _species;
}
#end
Only the superclass has access to the ivar _species. Your subclass should look like this:
- (NSString *)species {
NSString *value = [super species];
if (!value) {
self.species = #"Homo sapiens";
}
return [super species];
}
That sets the value to a default if it isn't currently set at all. Another option would be:
- (NSString *)species {
NSString *result = [super species];
if (!result) {
result = #"Home sapiens";
}
return result;
}
This doesn't update the value if there is no value. It simply returns a default as needed.
to access the superclass variables, they must be marked as #protected, access to such variables will be only inside the class and its heirs
#interface ObjectA : NSObject
{
#protected NSObject *_myProperty;
}
#property (nonatomic, strong, readonly) NSObject *myProperty;
#end
#interface ObjectB : ObjectA
#end
#implementation ObjectA
#synthesize myProperty = _myProperty;
#end
#implementation ObjectB
- (id)init
{
self = [super init];
if (self){
_myProperty = [NSObject new];
}
return self;
}
#end