iOS possible to access the super class iBoutlets objects in my subclass? - ios

I want to access super class iBoutlets objetcs in my subclass. Is that possible?. I am trying in the following way but am always getting nil.
Here is my code:
My super class
#import <UIKit/UIKit.h>
#interface SuperClassA : UIViewController {
}
#property (weak, nonatomic, getter=getDummyView) IBOutlet UIView *dummyView;
#end
#implementation SuperClassA
- (void)viewDidLoad {
[super viewDidLoad];
SubClassB *obj = [SubClassB new];
[obj printSuperClassiBouletObject];
}
#end
my subclass:
#import <UIKit/UIKit.h>
#interface SubClassB : SuperClassA {
}
#end
#implementation SubClassB
-(void)printSuperClassiBouletObject
{
NSLog(#"view: %#", [self getDummyView]);
}
#end
The above code gives me nil value always. Any idea how to get the actual iBoutlet object?. But when i pass the iBoutlet as an function argument then the object was not nil. In the super class i tried strong property, using #synthesize in implementation file but no helps. Any help that really might be appreciated.

My guess is that the problem is here:
SubClassB *obj = [SubClassB new];
[obj printSuperClassiBouletObject];
New will use default initializer, that will try to load nib with your class name, which is SubClassB. Do you have SubClassB.xib that set the outlet your project? If not, then SubClassB will be initialized with empty properties, by the default objc initializer.
Try this:
SubClassB *obj = [[SubClassB alloc] initWithNibName:#"SuperClassA"]; //or xib name that SuperClassA uses to initialize

There's nothing special about IBOutlet relative to the scope rules. You can inherit any property from super by including its declaration in the subclass. The simple way to do this is by placing those property declarations in the superclass's public interface (in superclass.h). Since we know that the subclass must import that, we know that everything in there will be available to the subclass.
A more complicated arrangement is required if you'd like the subclass to access the property but not other classes. These "protected" declarations need to go into a third header file that only the super and subclass import.
In other words... (simple case):
// MySuper.h
#interface MySuper : NSObject
#property (weak,nonatomic) IBOutlet UIView *someOutlet;
#end
// MySub.h
#import "MySuper.h"
#interface MySub : MySuper
// stuff for my sub
#end
Now both MySuper and MySub can refer to someOutlet
For "protected", something like this:
// MySuper.h
#interface MySuper : NSObject
// only public stuff here
#end
// MySuper-protected.h
#interface MySuper ()
#property (weak,nonatomic) IBOutlet UIView *someOutlet;
#end
// MySuper.m
#import "MySuper.h"
#import "MySuper-protected.h"
// MySub.h
// same as simple case
// MySub.m
#import "MySub.h"
#import "MySuper-protected.h"

Finally, i was able to achieve this by using this way!!!!
In my subclass i changed the method to:
-(void)printSuperClassiBouletObject:(SuperClassA*)superClassObj
and in my super class i am calling this way:
SubClassB *obj = [SubClassB new];
[obj printSuperClassiBouletObject:self];
And in my subclass i was access the super class objects and its variable from the super class instance it self.
Thanks for all the help !!!!!! :-)

Related

Property Inheritance in Objective C

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

How do you use UIView with properties or variables inherited from ViewController?

I have UIViewController named ParentViewController.h and .m
Then I added UIView inside this ParentViewController.
I had uiview.h and uiview.h added and assigned to UIView inside ParentViewController.
From
-(void)drawRect:(CGRect)rect {}
which is located in uiview.m, I need to access to properties inside ParentViewController.
How do I do this? Am I using UIView wrong?
ParentViewController.h
#import <UIKit/UIKit.h>
#interface ParentViewController : UIViewController
//I want my uiview to access this variable.
#property (nonatomic, strong) NSMutableArray *usedByUIView;
#end
ParentViewController.m
#import "ParentViewController.h"
#import "uiview.h"
#implementation ParentViewController
- (void)viewDidLoad {
...
}
#end
uiview.h
#import <UIKit/UIKit.h>
#interface uiview : UIView
#end
uiview.m
#import "uiview.h"
#implementation uiview
-(id) initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if(self){
}
return self;
}
- (void)drawRect:(CGRect)rect {
NSLog(#"start drawing using the data from usedByUIView");
}
#end
There are a few answers on this subject but, summarizing them, you don't, at least not the way that you're doing it. UIView's do not have access to their view controller's and aren't supposed to need access. Of course, in the real world, sometimes it's not worth the overhead of coding around independent views so people hack in access to the controller access. This can be done by keeping an instance variable in the view, pointing to the controller, and assigning a reference to it after the view has loaded, or by overriding the init so you also pass a view controller, or lots of other ways. But before you do that think through the logic of why you want access to the controller from the view and see if there isn't a different way to do it.

Objective-C: How do I access parent private properties from subclasses?

//Super class .h file
#interface MySuperClass : NSObject
#end
//Super class .m file
#interface MySuperClass ()
#property (nonatomic, strong) UITextField *emailField;
#end
#implementation MySuperClass
-(void)accessMyEmailField {
NSLog(#"My super email: %#", self.emailField.text);
}
#end
// ********** my subclass *******
//Subclass .h file
#interface MySubClass : MySuperClass
#end
//SubClass .m file
#interface MySubClass ()
#end
#implementation MySubClass
-(void)myEmail {
NSLog(#"My subclass email: %#", self.emailField.text);
}
-(void)setMyEmailFromSubclass{
self.emailField.Text = #"email#gmail.com"
}
#end
How do i access emailField in -(void)myEmail method.
How do i set email in Subclass -(void)setMyEmailFromSubclass; , and access it in super class accessMyEmailField
You can put accessors to these properties in a second header file, and import that file on a 'need-to-know' basis..
eg
mySuperClass+undocumentedProperties.h
#import "mySuperClass.h"
#interface mySuperClass(undocumentedProperties)
#property (nonatomic, strong) UITextField *emailField;
#end
mySuperClass.m
#import "mySuperClass+undocumentedProperties.h"
#interface mySuperClass()
///stuff that truly will be private to this class only
// self.emailField is no longer declared here..
#end
#implementation mySuperClass
#synthesize emailField; //(not really needed anymore)
/// etc, all your code unaltered
#end
mySubclass.h
#import "mySuperClass.h"
#interface mySubclass:mySuperClass
///some stuff
#end
mySubclass.m
#import "mySubclass.h"
#import "mySuperClass+undocumentedProperties.h"
#implementation
//off you go, this class is now 'aware' of this secret inherited property..
#end
obviously MySuperClass.m will have to import this .h file as well as its default one (or actually instead of, the default one is built in to this one), but your subclasses can import it too (directly into their .m file, so these properties remain private to the class. This is not a proper category because there is no corresponding mySuperClass+undocumentedProperties.m file (if you tried that you could not synthesize the backing iVars for these secret properties. Enjoy :)
Copy the private interface portion of the methods you want from your superclass - or in other words, in your Subclass.m file you would put:
#interface MySuperClass ()
#property (nonatomic, strong) UITextField *emailField;
#end
( place it above the existing #interface MySubClass () code )
Now your subclass knows that method exists in the superclass and can use it, but you are not exposing it to anyone else.
The whole point of private properties is exactly that and you should not want to access them. Because they are private they can change or be removed thus breaking the subclass that relies on them.
That being said they are not really private, just not "published". The can be called because Objective-C is a run-time dynamic language.

Creating properties only visible to subclass in Objective-C

I am attempting to create an abstract class and inherit some of its properties in a subclass. If I leave the properties in the abstract class' header file, all of the properties are accessible. The problem is that the instance of the subclass can also access those properties, which is not always desirable in my case.
For instance, I have a delegate in my abstract class that sends down button presses to its sub class. I realize that this may not be the best way of structuring inheritance, so other suggestions are welcome. However, I would still like to know how my subclass can inherit some properties from its superclass without making all of those properties available in its instance. Thanks in advance!
Here is some example code below:
#interface AbstractClass : UIView
#property (nonatomic, strong) id<ButtonDelegate>buttonDelegate;
#end
…
#protocol ButtonDelegate
#required
- (void) buttonWasPressed;
#end
…
#interface SubClass() <ButtonDelegate>
- (id)init {
self = [super init];
if (self) {
self.buttonDelegate = self;
}
return self;
}
-(void) buttonWasPressed {
[self doSomething];
}
…
#implementation ViewController
- (void)viewDidLoad {
SubClass *subClass = [[SubClass alloc] init];
subClass.buttonDelegate = self; // THIS IS NOT DESIRABLE
}
Do like UIGestureRecognizer does.
All public properties and methods goes into UIGestureRecognizer.h
All protected properties and methods goes into UIGestureRecognizerSubclass.h.
Only import this in the *.m-files. Never include it in any public header.
All private properties and methods goes into *.m-files. Use the #interface ClassName ()
Example https://gist.github.com/hfossli/8041396
how to my subclass can inherit some properties from its superclass
without making all of those properties available in its instance
What is the problem with this?
#import <Foundation/Foundation.h>
#interface Animal : NSObject
{
#protected
NSString *name; // default access. Only visible to subclasses.
}
#end
#implementation Animal
-(NSString*)description {
return name;
}
#end
#interface Cow : Animal
#end
#implementation Cow
-(id)init {
self=[super init];
if (self){
name = #"cow";
}
return self;
}
#end
int main(int argc, char *argv[]) {
#autoreleasepool {
Cow *cow = [Cow new];
NSLog(#"%#", cow); // prints the name through internal access
// error accessing from the outside: NSLog(#"%#", cow.name);
Animal *animal = [Animal new];
// error accessing from the outside: NSLog(#"%#", animal.name);
}
}
Maybe I misunderstood the question, you say
Creating properties only visible to subclass in Objective-C
and then
The problem is that the instance of the subclass can also access those
properties
Which one is it?
Create an empty category on top of your implementation file (.m):
#interface AbstractClass()
#property (nonatomic, strong) id<ButtonDelegate>buttonDelegate;
#end
In that way, your subclass will inherit and can access that property, but not other external classes because it's not in the header.
I don't think there is any way to achieve this using property declaration.
Either a property be visible for all (declared in .h file) or it will be invisible for all (declared in .m file using category)
I guess one way is declaring public/protected variable in .h file class declaration:
#interface AbstractClass : UIView {
...
id<ButtonDelegate>buttonDelegate;
...
}
#end
I am not sure about this, but give a try.
I see one approach that can fit your problem, however, it is pretty rude. Use Antonio's suggestion and create the private category with the property. As you've mentioned, it's scope is limited to the .m file. So you can put your subclasses into that file. This will be hard to read the code if subclasses are huge, but this is the only way for you as far as I understand.
EDIT: well, I have another solution. Copy
#property (nonatomic, strong) id<ButtonDelegate>buttonDelegate;
to all your subclasses. This will give you a warning about the absence of the property's #synthesize, but should work. I'd prefer this, if subclasses wont be changed or added often.
Let me describe how it would work.
We add a property into the Abstract class, and it is hidden for all (even for subclasses):
// .m file
#interface Abstract ()
#property (nonatomic, strong) id<ButtonDelegate> buttonDelegate;
#end
#implementation Abstract
#synthsize buttonDelegate;
#end;
But due to runtime features of Objective-C we still can call for that property, and there will not be any runtime error, only compiler warning.
To get rid of that warning and to add an ability to autocomplete, we add property without #synthsize into all subclasses:
#interface MySubclass : Abstract
#property (nonatomic, strong) id<ButtonDelegate> buttonDelegate;
#end
This will tell the compiler that there is such a property somewhere. There will be also one warning about the absence of #synthesize, but Xcode will still could autocomplete if you write something like
MySubclass *subclass = ...
subclass.butto...
It can not be done. There is no private or protected in objective-c. Stuff declared in the .m file "private" interface is only visible to that class and not in any subclass. Also you can always use your "private" properties/methods from outside if you want, although it would be bad practice to do so.

error with property in objective-c in iOS

I have started new iOS project and have added only one property in ViewControler header file. but it gives me error:
expected specifier-qualifier-list before 'property'
here is the code:
#import <UIKit/UIKit.h>
#interface QuoteGenViewController : UIViewController {
#property (retain) NSArray *myQuotes;
}
#end
Here the general structure of a class interface
#interface Class : Superclass
{
// Instance variable declarations.
// Theirs definition could be omitted since you can declare them
// in the implementation block or synthesize them using declared properties.
}
// Method and property declarations.
#end
Since a property provides a simple way to declare and implement an object’s accessor methods (getter/setter), you need to put them in the Method and property declarations section.
I really suggest to read ocDefiningClasses doc for this.
Hope that helps.
Your code should look like this:
#import <UIKit/UIKit.h>
#interface QuoteGenViewController : UIViewController {
}
#property (retain) NSArray *myQuotes;
#end

Resources