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

//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.

Related

How to make an Objective-C class conform to a protocol defined in Swift?

I have a class written in Swift where I've defined a protocol:
protocol PhotoIngestionDelegate {
func pictureTaken()
}
I am trying to have a class (CameraViewController) written in Objective-C conform to this protocol.
CameraViewController.h:
#import <GSSDK/GSSDK.h>
#protocol PhotoIngestionDelegate;
#interface CameraViewController : GSKCameraViewController <PhotoIngestionDelegate>
#end
CameraViewController.m:
#import "CameraViewController.h"
#import <GSSDK/GSSDK.h>
#import "EditFrameViewController.h"
#import "Scan.h"
#interface CameraViewController<PhotoIngestionDelegate> ()
#property (nonatomic, strong) UIView *toolbar;
#property (nonatomic, strong) UIButton *cameraButton;
#end
#implementation CameraViewController
...
The implementation in CameraViewController.m continues, but I cut it off to keep it brief. I know that I need to define the function pictureTaken() in CameraViewController.m, but I can't seem to get the delegate hookup to work. In CameraViewController.h I am getting that it Cannot find protocol definition for 'PhotoIngestionDelegate'.
Try this
#objc protocol PhotoIngestionDelegate {
}

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

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

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 !!!!!! :-)

Can't Resolve Type in Protocol

#import "MPOContactAuthorizationManager.h"
#protocol MPOContactAuthorizationManagerDelegate <NSObject>
- (void)authorizationManger:(MPOContactAuthorizationManager *)manager
didUpdateContactState:(ContactsState)contactState;
#end
MPOContactAuthorizationManager and ContactState are not resolving to types even though they are declared in MPOContactAuthorizationManager:
#import "MPOContactAuthorizationManagerDelegate.h"
typedef enum _contactsState {
kContactsStateUnknown,
kContactsStateAllowed,
kContactsStateDisallowed
} ContactsState;
#interface MPOContactAuthorizationManager : NSObject <UIAlertViewDelegate> {
ContactsState _contactsAuthorizationState;;
}
#property (strong, nonatomic) NSObject<MPOContactAuthorizationManagerDelegate> *delegate;
#property (nonatomic) ContactsState contactsAuthorizationState;
Any ideas as to why these are not resolving? Both are getting the error "Expected a type"
Thanks
Mike
You have a circular dependency. Update the MPOContactAuthorizationManagerDelegate.h header by getting rid of the #import line and adding the following:
#class MPOContactAuthorizationManager;
just before the #protocol line.
Just put both in one .h file (you still need the forward declaration for MPOContactAuthorizationManager):
typedef enum _contactsState {
kContactsStateUnknown,
kContactsStateAllowed,
kContactsStateDisallowed
} ContactsState;
#class MPOContactAuthorizationManager;
#protocol MPOContactAuthorizationManagerDelegate <NSObject>
- (void)authorizationManger:(MPOContactAuthorizationManager *)manager
didUpdateContactState:(ContactsState)contactState;
#end
#interface MPOContactAuthorizationManager : NSObject <UIAlertViewDelegate> {
ContactsState _contactsAuthorizationState;;
}
#property (strong, nonatomic) NSObject<MPOContactAuthorizationManagerDelegate> *delegate;
#property (nonatomic) ContactsState contactsAuthorizationState;
Replace the import of "MPOContactAuthorizationManagerDelegate.h" from MPContactAuthorizationManager.h by using a forward declaration of the protocol:
#protocol MPOContactAuthorizationManagerDelegate;
typedef enum _contactsState {
kContactsStateUnknown,
kContactsStateAllowed,
kContactsStateDisallowed
} ContactsState;
#interface MPOContactAuthorizationManager : NSObject <UIAlertViewDelegate> {
ContactsState _contactsAuthorizationState;;
}
........
You need to choose this import scheme as you are referring to a user defined type (the ContactsState type) in the protocol's header - so this header needs to import the manager's header. In the manager's header, however, you only refer to the protocol as the types of the method parameters, so you can legally forward-declare here.
In general, you should only import one header from another in a few cases:
Declaring a class in your header that's a subclass of a class defined in the other header
Referring to user defined types (e.g. via a typedef) in your header that are defined in the other header
Declaring a class in your header as conforming to a protocol declared in another header
Declaring a category in your header for a class defined in another header
I think I'm forgetting one, so saving this space for that one.
Also - read this enlightening answer.
The more common case of needing protocol and class names in public method parameters and properties can be accomplished using forward declarations with #class and #protocol. Although, if it were me, I'd keep the protocol declaration in the same header as the authorization manager - seems more convenient that way. Note that you will need to do a forward-declaration within the file for this. For example:
typedef enum _contactsState {
kContactsStateUnknown,
kContactsStateAllowed,
kContactsStateDisallowed
} ContactsState;
//forward-declare the protocol before referencing it in the file
#protocol MPOContactAuthorizationManager;
#interface MPOContactAuthorizationManager : NSObject <UIAlertViewDelegate> {
ContactsState _contactsAuthorizationState;;
}
#property (strong, nonatomic) NSObject<MPOContactAuthorizationManagerDelegate> *delegate;
#property (nonatomic) ContactsState contactsAuthorizationState;
........
#end
// Provide the real protocol declaration.
#protocol MPOContactAuthorizationManagerDelegate <NSObject>
- (void)authorizationManger:(MPOContactAuthorizationManager *)manager
didUpdateContactState:(ContactsState)contactState;
#end

Why do default Storyboard apps have a second interface declaration

Sorry if this is stupid... but it confuses me?...
I'm trying a new storyboard app with Xcode and just asked myself why there is a second declaration of the #interface in my implementation file?
.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController {
}
#end
.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
....
#end
See Apple's documentation: https://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocCategories.html
It's a class extension, subtly different from a category, since it has no name inside the parentheses. You use it for declaring properties and methods that are intended to be kept private (out of the header), and redeclaring publicly read-only properties and methods as privately read-write. This allows for cleaner encapsulation.
By request, a friendly example:
JYDuckPondManager.h
#interface JYDuckPondManager : NSObject
#property (nonatomic, assign, readonly) NSUInteger duckCount;
#property (nonatomic, assign, readonly) CGFloat waterLevel;
- (JYDuckReaction *)feedDucks:(JYDuckFood *)food;
- (JYDuckReaction *)harassDucks:(JYDuckTaunt *)taunt;
#end
JYDuckPondManager.m (extension, imaginary implementation omitted)
#interface JYDuckPondManager ()
//// Redefined for internal modification
#property (nonatomic, assign, readwrite) NSUInteger duckCount;
#property (nonatomic, assign, readwrite) CGFloat waterLevel;
//// Internally exclusive properties
#property (nonatomic, strong) NSSet *duckPersonalitySet;
#property (nonatomic, assign) CGFloat flockAnxietyLevel;
//// Private messages
- (void)recalculatePondState;
#end
Other objects should be able to interact with the pond, but they're not supposed to know certain things going on in the pond or redefine the pond's statistics. Keeping nuts-and-bolts stuff in the .m extension ensures that the .h is concise and appropriately limited.
The second #interface block in the .m file is an extension. You could add declarations for methods and instance variables you want to use internally within your class.
The second interface #interface ViewController () is a class extension which is like an anonymous category. A class extension is declared like a category only without a name. Declarations found in these extensions directly extend the declarations found in the class’s primary #interface and can sometimes (in some situations) override declarations found in the primary interface.

Resources