I have a base class Person and would like to create a derived class that would not have any custom implementation - all properties and methods are declared and implemented in the base class. I get errors saying:
Cannot find interface declaration for 'Person', superclass of 'Employee';
Class 'Employee' defined without specifying a base class.
I am probably missing something; please help. How do I fix those errors?
Person.h
#interface Person : NSObject
#end
Person.m
#import "Person.h"
#interface Person ()
#property (nonatomic, strong) NSString *name;
#end
#implementation Person {}
- (void)print {
NSLog(#"Name: %#", name);
}
#end
Employee.h
#interface Employee : Person
#end
Employee.m
#import "Employee.h"
#implementation Employee {}
#end
Related
In my code I have the following compiler warning:
Initializing 'MyClass *__strong' with an expression of incompatible type '__strong id<MyProtocol>'
My question is this, why does the compiler warning go away if I remove the protocol from the category?
As in, when when I replace
#interface MyClass (CategoryNameHere) <SomeOtherProtocol>
With
#interface MyClass (CategoryNameHere)
I have found minimal piece of code which reproduces this scenario:
#interface MyWidget ()
#end
#protocol MyProtocol
#end
#protocol SomeOtherProtocol
#end
#interface MyClass <MyProtocol>
#end
#interface MyClass (CategoryNameHere) <SomeOtherProtocol>
#end
#implementation MyWidget
- (MyClass *)sampleMethod:(id<MyProtocol>)v {
MyClass *instance = v;
return instance;
}
#end
The compiler warning is on the line which contains
MyClass *instance = v;
#interface Factory : NSObject #end
#protocol First #end
#protocol Second #end
#protocol Third #end
#interface Base <First, Second> #end
#interface Custom : Base #end
#interface Base (CategoryNameHere) <Second>
#end
#implementation Factory
- (Custom *)sampleMethod:(id<First, Second>)v {
return v;
}
#end
Consider example that you have provided with several renaming.
You can play with it by adding/removing protocols as requirement for Factory's method or by adding/removing protocols as extensions for classes.
The corner stone of this example is bare ( without superclass ) class Base.
It is considered as id<First, Second> by compiler.
So basically I am creating 2 classes here:
Patient and Doctor
and what I want to do is that I want to create an instance method called "requestMedicationForPatient" that takes a patient instance as a parameter.
So I did something like this
-(void)requestMedicationForPatient: (Patient*) patient;
in the Doctor.h file.
and also I already imported Patient.h file in both Doctor.h and Doctor.m files.
Why doesn't it work?
Patient.h:
#import <Foundation/Foundation.h>
#import "Doctor.h"
NS_ASSUME_NONNULL_BEGIN
#interface Patient : NSObject
#property NSString* name;
#property NSInteger age;
#property (nonatomic) BOOL hasValidHealthCard;
- (instancetype)initWithName:(NSString*) name andAge: (int) age;
#end
NS_ASSUME_NONNULL_END
Patient.m:
#import "Patient.h"
#import "Doctor.h"
#implementation Patient
- (instancetype)initWithName:(NSString*) name andAge: (int) age
{
self = [super init];
if (self) {
_age = age;
_name = name;
}
return self;
}
#end
Doctor.h:
#import <Foundation/Foundation.h>
#import "Patient.h"
NS_ASSUME_NONNULL_BEGIN
#interface Doctor : NSObject
#property (nonatomic)NSString* name;
#property (nonatomic)NSString* specialization;
#property (nonatomic)NSMutableSet* patients;
- (instancetype)initWithName: (NSString*) name andSpecialization: (NSString*) specialization;
-(void)requestMedicationForPatient: (Patient*) patient;
#end
NS_ASSUME_NONNULL_END
Doctor.m:
#import "Doctor.h"
#import "Patient.h"
#implementation Doctor
- (instancetype)initWithName: (NSString*) name andSpecialization: (NSString*) specialization
{
self = [super init];
if (self) {
_name = name;
_specialization = specialization;
}
return self;
}
#end
I should be able to create that method with a parameter of type Patient right ? But it says Expected a type.
You are importing Patient.h into Doctor.h and you are importing Doctor.h into Patient.h. Always avoid such circular imports. Also avoid needlessly importing a header file in another header file.
Nothing in Patient.h references anything from Doctor.h so you should not be importing Doctor.h in your Patient.h file.
You should also remove the import of Patient.h from Doctor.h. To make the compiler happy, you can provide a forward reference to Patient using #class Patient;.
Your updated Doctor.h should be:
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
#class Patient;
#interface Doctor : NSObject
#property (nonatomic) NSString* name;
#property (nonatomic) NSString* specialization;
#property (nonatomic) NSMutableSet* patients;
- (instancetype)initWithName:(NSString *)name andSpecialization:(NSString*)specialization;
- (void)requestMedicationForPatient:(Patient *)patient;
#end
NS_ASSUME_NONNULL_END
I learned that give two class subA and A, when subclass access superclass property directly(without super call) need some workaround, below is one of them I found
#interface A : NSObject
#property (nonatomic, strong) NSString * name;
#end
#interface subA : A
#end
#implementation subA
#synthesize name = _name;
- (void)setName(NSString *)name {
_name = name;
}
#end
the question is that #synthesize in the subA looks as if it re-synthesized a new iVar, is that true?
Is it possible to encapsulate the fact that my class is derived from a certain superclass? Something like:
#class NoneOfYourBusiness;
#interface MyClass : NoneOfYourBusiness
#end
The compiler doesn’t like this: Attempting to use the forward class 'NoneOfYourBusiness' as superclass of 'MyClass'.
You could add some indirection; a dummy superclass in the inheritance tree, between MyClass and RealSuperclass:
Private header, HiddenSuperclass.h, with corresponding implementation file
#import <Foundation/Foundation.h>
#interface HiddenSuper : NSObject
- (void)makePancakes;
#end
Header for dummy class, corresponding empty implementation
#import <Foundation/Foundation.h>
#import "HiddenSuper.h"
#interface DummySuper : HiddenSuper
// Nothing to see here, folks!
#end
Then your public class's header:
#import "DummySuper.h"
#interface PublicSubclass : DummySuper
- (void)fixBreakfast;
#end
And the implementation, hidden by compilation:
#import "PublicSubclass.h"
#import "HiddenSuper.h"
#implementation PublicSubclass
- (void)fixBreakfast
{
[self makePancakes];
}
#end
Two answers
The requirement makes no sense. Client code can see the super class does not mean anything because it should be empty.
i.e. Thats all they can see
#interface NoneOfYourBusiness : NSObject
#end
#interface MyClass : NoneOfYourBusiness
- (void)publicMethod;
#end
because you should put all private / internal method / variable in private header / implementation file.
Ok you really need to hide it for some reason, then hide everything
public header
#interface MyClass : NSObject
- (void)publicMethod;
#end
private header / implementation file
#interface NoneOfYourBusiness : NSObject
#end
#interface MyClassImpl : NoneOfYourBusiness
- (void)publicMethod;
#end
#interface MyClass ()
#property (strong) MyClassImpl *impl;
#end
#implementation
- (id)forwardingTargetForSelector:(SEL)aSelector
{
return self.impl;
}
#end
you can even make MyClass inherited from NSProxy to make it a real proxy object
I need to have property in class that is excluded from public framework headers, but it is available for use internally in other framework classes.
What I did right now is:
MyClass.h:
#interface MyClass: NSObject
#end
MyClass+Internal.h
#interface MyClass (Internal)
#property (nonatomic, copy) NSString *mySecretProperty;
#end
MyClass.m
#import "MyClass.h"
#import "MyClass+Internal.h"
#interface MyClass ()
#property (nonatomic, copy) NSString *mySecretProperty;
#end
#implementation MyClass
#end
And I can use private property like:
MyOtherClass.m:
#import "MyClass.h"
#import "MyClass+Internal.h"
#implementation MyOtherClass
- (void)test {
MyClass *myClass = [MyClass new];
NSLog(#"%#", myClass.mySecretProperty)
}
#end
But what I don't like about this setup is that I have duplicate declaration of property in my Internal Category and inside of anonymous Category.
Is there a way to improve this setup?
I think you could do with the class extension only, there is no need to use a category. The quick fix would be to remove the category name from the parenthesis, transforming it into the class extension, then remove the class extension declaration from the .m file.
After this you only import the extension header in your framework classes and you make sure it is a private header of your framework.
MyClass.h
#interface MyClass: NSObject
#end
MyClass+Internal.h
#import "MyClass.h"
#interface MyClass ()
#property (nonatomic, copy) NSString *mySecretProperty;
#end
MyClass.m
#import "MyClass.h"
#import "MyClass+Internal.h"
#implementation MyClass
#end
MyOtherClass.m:
#import "MyClass.h"
#import "MyClass+Internal.h"
#implementation MyOtherClass
- (void)test {
MyClass *myClass = [MyClass new];
NSLog(#"%#", myClass.mySecretProperty)
}
#end
The key is understanding the difference between categories and class extensions, see here: https://stackoverflow.com/a/4540582/703809