Accessing Sub class member from base class in objective c - objective-c

i tried to access the subclass member variable from base class. But i can't access it. It returns a null value..
for eg..
I have baseclass classA and Subclass ClassB. i tried to access the classB member variable say x from base class ClassA. but it returns null. i assigned classB variable with some value.
i tried like this..
In classA.h
#classB
#property (nonatomic, retain) classB *BObj;
In classA.m
#import classB.h
#synthesize BObj;
BObj = [[classB alloc]init];
NSLog(#"%d",BObj.x); //returns NULL
In ClassB.h
#interface ClassB :ClassA
#property(nonatomic,retain) int x;
In ClassB.m
#synthesize x;
x = 10; //This value should be read from super class(Class A).

As Chuck says in comments, this doesn't look like real code. Where are you setting x to 10? If it isn't in your init method, or in a method called from init, it won't display. And you have invalidated your complaint with your edit - logging %d will not show null, it will show zero.

Try this : NSLog(#"%d", BObj.x);

Related

How can I add values to NSArray of different class A from Class B

I have my .m file where I need to update NSArray of class B, where I should be able to the values from that array.
I am trying this in Class A
// TabHeaderViewModel.h
typedef enum {
UsePassHeaderType,
ManageCardType
}TabHeaderType;
NS_ASSUME_NONNULL_BEGIN
#interface TabHeaderViewModel : NSObject
#property (nonatomic) TabHeaderType headerType;
- (instancetype)initWithHeaderType:(TabHeaderType)headerType;
- (NSArray *)dataSourceForHeaderModel;
#end
And now I want to access datatSourceForHeaderModel from class B in its .m file
TabHeaderViewModel *headerVM = [[TabHeaderViewModel alloc]initWithHeaderType:ManageCardType];
headerVM.dataSourceForHeaderModel = self.dataSourceForHeader;
// getting error - No setter method 'setDataSourceForHeaderModel:' for assignment to property
either code in interface
#property (nonatomic) NSArray *dataSourceForHeaderModel;
or
-(void)setDataSourceForHeaderModel:(NSArray*)datasource;
also do your implementation when you define a method if there is processing.
But its easier to go with the property solution.

Private v/s Public class properties in Objective C

Trying to make my OOP fundamentals strong based of objective C. Sorry if my explanation is too long.
I have 3 classes in my app as Class A, Class B and Class C objective C classes.
I have a property of class A in my implementation of class B i.e. it makes private property of class B.
// implementation Class B
#interface ClassB ()
#property (nonatomic, strong) ClassA *classA;
#end
I create an instance of class B in one of my class C methods and try to access class A property through class B's instance in class C.
// implementation Class C
#interface ClassC ()
#property (nonatomic, strong) ClassB *classB;
#end
#implementation ClassC
- (void)someMethod
{
NSString *string = [[NSString alloc] init];
classB = [[ClassB alloc] init];
string = classB.classA.displayString; //get an error here - ClassB doesn't have classA.
}
#end
To avoid the error I moved the classA property from implementation to header in ClassB.
// header Class B
#interface ClassB : NSObject
#property (nonatomic, strong) ClassA *classA;
#end
But I am worried that anybody class can create an instance of class B, access classA property and can then use/modify the properties which are part of class A.
Question: Is it a good style to move the classA property to the header file of Class B so I can use it in Class C or should I create a method in Class B which returns me whatever I need from class A? Something like:
#implementation ClassB
- (NSString*)displayStringOfClassA
{
classA = [[ClassA alloc] init];
return self.classA.displayString;
}
#end
In ClassB.h:
#interface ClassB: NSObject
#property (nonatomic, strong, readonly) ClassA *classA;
#end
In ClassB.m:
#interface ClassB()
#property (nonatomic, strong, readwrite) ClassA *classA;
#end
Also, strong and readwrite are default modifiers - you can get rid of them. However, they improve code readability.
EDIT: if you want to forbid access for ClassA properties - do the same trick. Suggested above code will forbid only to modify classA property of classB. For ClassA's displayString:
In ClassA.h:
#interface ClassA: NSObject
#property (nonatomic, strong, readonly) NSString *displayString;
#end
In ClassA.m:
#interface ClassA()
#property (nonatomic, strong, readwrite) NSString *displayString;
#end
I would suggest a readonly string property in ClassB.h.
ClassB.h:
#property (nonatomic, readonly) NSString *classAString;
ClassB.m:
- (NSString *) classAString
{
return self.classA.displayString;
}
This acts as a "getter" method for the particular string you need, and avoids others getting access to classA.
Edit:
Others suggested adding classA as a readonly property in ClassB.h. This will still allow modification of classA properties, it will only guarantee that classA is not reassigned to another ClassA instance.
Sounds like you want "framework", not "private" #property() declarations.
To do this, create a file like:
ClassA_Private.h
That contains your #property() declaration.
Then #import "ClassA_Private.h" in both your ClassA.m (prior to the #implementation) and in any subclasses that want to use that #property.
This was a secondary design consideration when creation class extensions; adding the ability to have #property declarations that are fully accessible across subclasses and/or within frameworks without being exposed externally. While you can't create a framework for an iOS targeted application, the same functionality still applies.
Something like string = objectB.objectA.displayString; is violating the Law of Demeter. Designing according to the Law of Demeter results in more maintainable and adaptable software.
You should always try to not talk to strangers. That is in your example: self talks to objectB and objectB talks to objectA but self shouldn't talk to objectA because it's a stranger.

Member variable declared in .m file keeps its value between instances of the class

I have the follow implementation file for MyClass:
BOOL myBool;
#implementation MyClass
// ...
- (void) someMethod {
myBool = YES;
}
#end
It seems like myBool will be YES for every instance of MyClass after someMethod is called on just one instance of MyClass. However if I define myBool like this it has a unique value for each instance of MyClass:
#interface MyClass ()
#property (nonatomic) BOOL myBool;
#end
What is the difference between the above two "member variable" syntaxes?
The difference is that in 1st case it is not member variable, it is global variable so it naturally persists its value between multiple instances of your class.
If you want to declare ivar in class implementation file you can do the following:
#implementation MyClass{
BOOL myBool;
}
...

Property Declaration - ivar and getter values don't match

I have a doubt regarding property redeclaration
Overview:
class "A" is the parent class with a readonly property int n1;
class "B" is the subclass, which redeclares the property as read write
using the setter of class "B" the property value is set as 20
when i print the value using the getter and the instance variable I seem to get different values
Points to note: - Memory management = ARC (Automatic Reference Counting)
Question:
When I print the values of self.n1 and _n1 why do I get different values ?
My expected behavior and actual behavior don't match why (Pls scroll down to see the actual vs expected) ?
Code: (in separate files)
A.h
#import<Foundation/Foundation.h>
#interface A : NSObject
#property (readonly) int n1;
- (void) display;
#end
A.m
#import "A.h"
#implementation A
#synthesize n1 = _n1;
- (void) display
{
printf("_n1 = %i\n", _n1); //I expected _n1 and self.n1 to display the same value
printf("self.n1 = %i\n\n", self.n1); //but they seem to display different values
}
#end
B.h
#import"A.h"
#interface B : A
#property (readwrite) int n1;
#end
B.m
#import"B.h"
#implementation B
#synthesize n1 = _n1;
#end
test.m
#import"B.h"
int main()
{
system("clear");
B* b1 = [[B alloc] init];
b1.n1 = 20;
[b1 display]; //Doubt - my expected behavior is different from actual behavior
return(0);
}
Expected Behavior:
_n1 = 20
self.n1 = 20
Actual Behavior:
_n1 = 0
self.n1 = 20
There are two ways of going about this. In neither case do you call #synthesize in the subclass. I'm surprised that compiles for you. I would expect an error like "Property 'n1' attempting to use ivar '_n1' declared in superclass 'A'". In any case it's definitely not something you can really do, which is why you're seeing strange behavior. (I remembered why you aren't seeing this error; it's because of the separate compile units. You're just winding up with different ivars.)
First, you need to understand #dyanmic. This is a way of telling the compiler "yes, I know you don't see an implementation for the required method here; I promise it'll be there at runtime." In the subclass, you will use #dynamic to let the compiler know that it's ok to inherit n1.
#implementation B
#dynamic n1;
#end
Now, you need to provide the setN1: method. IMO, subclasses shouldn't go messing with their superclass's ivars, so I approve of the fact that synthesized ivars are marked #private. In a second, I'll tell you how to undo that, but for now let's deal with my preferred solution:
Implement setN1: as a private method in A.
Expose it in B.
A.h
#interface A : NSObject
#property (readonly) int n1;
- (void) display;
#end
A.m
#import "A.h"
#interface A () // Private class extension, causes setN1: to be created but not exposed.
#property (readwrite) int n1;
#end
#implementation A
#synthesize n1 = _n1;
- (void) display {
...
}
#end
B.h
#import "A.h"
#interface B : A
#property (readwrite) int n1; // Tell the world about setN1:
#end
B.m
#import "B.h"
#implementation B
#dynamic n1; // Yes compiler, setN1: exists. I promise.
#end
Now, some people think it's fine for subclasses to mess with their superclass's ivars. Those people are wrong (ok, IMHO...) but it is possible in ObjC. You just need to declare the ivar #protected. This is the default when you declare ivars directly in the #interface (one of many reasons you shouldn't do this anymore). It would look like this:
A.h
#interface A : NSObject {
int _n1;
}
...
A.m -- remove the extra class extension that makes n1 writable in the superclass.
B.h -- no change
B.m
#implementation B
#dynamic n1;
- (void)setN1:(int)n1 {
_n1 = n1;
}
#end
I copied your code and verified the behavior that you are getting. I can explain the mechanics of it, but not the logic behind it.
Here is what's going on: each of the two #synthesize directives produces a hidden variable _n in its corresponding class. In addition, the directive synthesizes a getter for n1 in A, and a getter/setter pair in B. The getter of n1 in B overrides the getter of n1 in A; the setter does not, because there is nothing to override.
At this point, A's _n1 in B becomes orphaned: neither the getter of n1 nor its setter reference it. The setter references B's _n1, not A's. That's why you are seeing different values printed in the display method of A. Putting the method in B behaves the way that you would expect.
EDIT:
Naturally, the next question is how to make the behavior that you want. It turns out to be simple: do not synthesize the property in B, and implement a setter of _n1 in A's implementation file (without putting it in the interface, so that it remains read-only to the clients of your interface).
// This goes in A.m without a declaration in A.h
- (void) setN1:(int)n1 {
_n1 = n1;
}

How can I access a value in a class which was set in another class in objective c?

I have two classes, classA and classB.
I navigated from classA to classB.
I set a value
Temp = 0; in classB.
I popped back to classA from classB.
Now, I need to access Temp value in classA.
how can I get that without setting the value in AppDelegate calss ?
You should use a Property. Have a look at the apple tutorial
#interface MyClass : NSObject
{
NSString *value;
}
#property(copy, readwrite) NSString *value;
#end
#implementation MyClass
#synthesize value;
#end
In another class that has a instance of MyClass
myInstanceOfMyClass.value = #"hi"; // Sets the value to 'hi'
NSString* myString = myInstanceOfMyClass.value; // Gets the value :)
I guess, there are two ways to do this:
Create owner object in class B and initialize it with class A's object. When done with class B, set the value in class A's variable and then use it into class A
Create a property in App Delegate and assign this variable from Class B. When back to class A, use the variable from App Delegate.