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
Related
I have created a very basic Objective-C class.
MyClass.h
#interface MyClass: NSObject
#end
MyClass.m
#import "MyClass.h"
#interface MyClass()
#end
#implementation MyClass: NSObject {
NSMutableArray* _myArray;
}
#end
Xcode is showing the following warning on the #implementation line:
Class implementation may not have super class
The warning goes away if I remove the NSMutableArray* _myArray; line.
What does this warning mean? What am I doing wrong?
Delete NSObject in the implementation part. The super class has to be specified only in the interface.
#implementation MyClass {
NSMutableArray* _myArray;
}
#end
#implementation MyClass: NSObject
You're not supposed to inherit from NSObject in the implementation.
you already got it in the #interface MyClass: NSObject
//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.
I am new to test driven development and have a basic question. How do I access private properties for unit testing? There are plenty of answers on how you access methods but I couldn't find much on properties. Here is what I've got now for my class CDTest. Excluding some of the imported headers for readability purposes.
CDTest.h
#interface CDTest : NSObject
#end
CDTest.m
#import "CDTest.h"
#import "CDTest+Protected.h"
#interface CDTest()
#property (strong, nonatomic) NSManagedObjectContext *context;
#end
#implementation CDTest
- (void)setup
{
//Sets up the context
}
#end
CDTest+Protected.h
#interface CDTest()
- (void)setup;
#end
Unit test .m file
#import "CDTest.h"
#import "CDTest+Protected.h"
#implementation CDTestTests
{
CDTest *cdTest;
}
- (void)setUp
{
[super setUp];
cdTest = [CDTest new];
}
- (void)testSetup
{
[cdTest setup];
//Now I need access to the properties in cdTest to validate them
}
#end
In Objective-C properties are methods (each property is a getter and a setter if it is read/write).
Just declare your property in your protected category, which should be declared something like this
#interface CDTest(Protected)
- (void)setup;
#property (strong, nonatomic) NSManagedObjectContext *context;
#end
I'm trying to access to another class from my viewcontoller but is not working:
viewcontroller.h
#import <UIKit/UIKit.h>
#class firstClass; //nsobject class
#interface ViewController : UIViewController
{
firstClass *firstclass;
}
#property (retain,nonatomic) LEMZfirstClass *firstclass;
---
firstClass.h:
#import "LEMZViewController.h"
#interface firstClass : NSObject
{
ViewController *viewController;
}
#property (retain,nonatomic) ViewController *viewController;
-(void)doSomenthing;
firstClass.m:
#synthesize viewController;
-(void)doSomenthing
{
viewController.firstclass=self;
viewController.outPutLabel.text=#"This is my Label";
}
viewcontroller.m:
#synthesize firstclass;
- (void)viewDidLoad
{
[super viewDidLoad];
[firstclass doSomenthing];
}
it compiles with no errors but the label is never updated and for that matter the first class is never call it all. What I'm doing wrong? I'll really appreciate your help.
A few things I'm noticing:
Generally you would have the ViewController class handle updating its own UI elements, not another class.
Where is your outPutLabel variable? Is it created by code or an IBOutlet that is wired up in InterfaceBuilder?
Before you can call something on firstclass, you must create it. Something like this:
firstclass = [[firstClass alloc] init];
[firstclass doSomenthing];
The viewController.firstclass=self; line would be redundant then.
Your firstClass.h
#import <Foundation/Foundation.h>
#interface firstClass : NSObject
+(NSString *)doSomenthing; //Instance Class
#end
firstClass.m
#import "firstClass.h"
#implementation firstClass
+(NSString *)doSomenthing
{
return #"This is my Label";
}
#end
ViewController.h
#import <UIKit/UIKit.h>
#import "firstClass.h"
#interface ViewController : UIViewController
#end
ViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
[firstClass doSomenthing];
outPutLabel.text=[firstClass doSomenthing];;
// Do any additional setup after loading the view, typically from a nib.
}
Note: Here I am using instance class. Before you work this code you must study about Instance class.
I know this is a newbie question, but I am all confused. How should I call class method from another class, or shouldn't I?
Here is my ClassA and CoreDataHelper:
#import <Foundation/Foundation.h>
#interface ClassA : NSObject {
}
#property (nonatomic, retain) NSString * sessionId;
#property (nonatomic, retain) NSString * token;
#property (nonatomic, retain) NSString * userid;
+ (void) pullOfflineDataWithContext:(NSManagedObjectContext *)managedObjectContext ;
#end
#import "ClassA.h"
#import "CoreDataHelper.h"
#implementation ClassA
+ (void) pullOfflineDataWithContext:(NSManagedObjectContext *)managedObjectContext {
// get Contacts, Accounts, Meetings into Core Data
bool asd =[CoreDataHelper insertAllObjectsForEntity:#"Contact" andContext:managedObjectContext initCoreData:jsonDict];
}
#end
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#interface CoreDataHelper : NSObject
//For inserting objects
+(BOOL)insertAllObjectsForEntity:(NSString*)entityName andContext:(NSManagedObjectContext *)managedObjectContext;
#end
You are calling a class method from another in the right way except the method signature is not the same as it is declared;
bool asd =[CoreDataHelper insertAllObjectsForEntity:#"Contact"
andContext:managedObjectContext
initCoreData:jsonDict];
The declaration of +insertAllObjectsForEntity:andContext: does not have the last one in the calling code above
+(BOOL)insertAllObjectsForEntity:(NSString*)entityName
andContext:(NSManagedObjectContext *)managedObjectContext;
Like:
[ClassName method];
Instead of:
[instance method];
In your example would be then:
[ClassA pullOfflineDataWithContext];