inheritance & objective-c - objective-c

this is my h file:
#import <Foundation/Foundation.h>
#interface Base : NSObject
#end
this is my m file:
#import "Base.h"
#interface Base()
#property (nonatomic) int number;
#end
#implementation Base
-(void) setNumber: (int) p_number
{
self.number = p_number;
}
#end
this is what i want to accomplish
an h file:
#import <Foundation/Foundation.h>
#import "Base.h"
#interface Derived : Base
#end
and to do this in the m file
#import "Derived.h"
#implementation Derived
- (void) foo
{
self.number= 7;
}
#end
this of course results in error, please answer with a code that allows me to call the base property without placing the definition in the h file
thanks

Asking people to answer only with code is not a good idea. Why not ask for an explanation of what's wrong, so that you can fix this error and tons of similar errors in the future yourself?
The problem here is that you don't declare your property in the base header. If you don't want to do that, you can declare it in your subclass' implementation file as an extension of your base class:
Derived.m
#import "Derived.h"
#interface Base ()
#property (nonatomic) int number;
#end
#implementation Derived
- (void) foo
{
self.number= 7;
}
#end

You could use the same approach that Apple uses with UIGestureRecognizerSubclass.h
e.g. Create
// BaseSubclass.h
#interface Base (ForSubclassEyesOnly)
#property (nonatomic, assign) NSInteger number;
#end
You'll need to silence the compiler with
#implementation Base (ForSubclassEyesOnly)
#dynamic number;
#end
Now any class that want's to use these properties/call methods just includes this header.
e.g
#import "Derived.h"
#import "BaseSubclass.h"
#implementation Derived
- (void) foo
{
self.number = 7;
}
#end

Related

Why does adding this protocol to this category trigger a compiler warning?

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.

Expected a type error when trying to create a class method with parameter of another class after importing header files

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

Accessing category method in original Objective C class

I have a class for which I have created a category. Now I want to access category method inside original class but I am getting error:
error: instance method '-hasSound' not found (return type
defaults to 'id') [-Werror,-Wobjc-method-access]
// Animal.h
#interface Animal: NSObject
- (void)sound;
#end
// Animal.m
#import "Animal+Additions.h"
#implementation Animal
- (void)sound {
[self hasSound];
}
#end
// Animal+Additions.h
#interface Animal (Additions)
- (BOOL)hasSound;
#end
// Animal+Additions.h
#implementation Animal (Additions)
- (BOOL) hasSound {
return YES;
}
#end
I have been doing same thing in Swift but not sure how to achieve the same thing in Objective C.
Category and original class are in separate files. I have imported Category interface file inside original class but that didn't work.
You have not shown sufficient #import statements, so I have to assume they don't exist. You need them.
Another possible issue is that, at least according to your comments, you seem to have two Animal+Additions.h files but no Animal+Additions.m file.
This complete code in four files compiles for me:
// Animal.h
#import <Foundation/Foundation.h>
#interface Animal: NSObject
- (void)sound;
#end
// Animal.m
#import "Animal.h"
#import "Animal+Additions.h"
#implementation Animal
- (void)sound {
[self hasSound];
}
#end
// Animal+Additions.h
#import "Animal.h"
#interface Animal (Additions)
- (BOOL)hasSound;
#end
// Animal+Additions.m
#import "Animal+Additions.h"
#implementation Animal (Additions)
- (BOOL) hasSound {
return YES;
}
#end
Note all the #import statements, and note that the Animal.m file must be part of the target.

Can I hide my superclass from the users of my class?

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

Hiding properties from public framework headers, but leaving available internally

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