Can I hide my superclass from the users of my class? - objective-c

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

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.

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

Delegate twice within 2 class or call each other function in 2 class

Basically, I want to call function from one class to another.I know I need to do delegate.
However, for example, there is class A and B. I need to call function in class A from class B and I also need to call function in class B from class A.
As a result, I need to import like
import "classA.h" //to do in class B
import "classB.h" //to do in class A
//then i may have delegate like this in both class
#protocol emailingroupViewControllerDelegate <NSObject>
-(void)updateGroupEmail :(NSString *)inputKey;
#end
The problem is that it didn't allow me to import like this in between two class. How should I do?
You have a dependency cycle in your headers. It's easy to work around; instead of including the other class' header file in each header, you use the #class directive and include the header file in the implementation file.
In classA.h, do this:
#class ClassB
#interface ClassA
...
#end
In classA.m, do this:
#import "classA.h"
#import "classB.h"
#implementation ClassA : NSObject
...
#end
In classB.h, do this:
#class ClassA
#interface ClassB
...
#end
Finally, in classB.m, do this:
#import "classB.h"
#import "classA.h"
#implementation ClassB : NSObject
...
#end
However, if you're trying to use the delegate pattern, your delegate should implement a protocol rather than be an explicit class. You should set up the connection between the delegate and the object that uses it in a third class. This would be the header for ClassA:
#protocol SomeDelegate <NSObject>
- (void)classA:(ClassA *)classA didSomethingWithAString:(NSString *)string;
#end
#interface ClassA : NSObject
#property (weak, nonatomic) id <SomeDelegate> delegate;
#end
However, again, if what you're trying to do is just have ClassA call a function in ClassB, which can call a function in ClassA, you might want to re-examine the way you've designed your classes.

Forward declaration error

I have a protocol like this:
#import <Foundation/Foundation.h>
#protocol Prot1 <NSObject>
#required
- (void)methodInProtocol;
#end
This is a protocol for a delegate I want to store in a class like this:
#import <Cocoa/Cocoa.h>
#class Prot1;
#interface Class1 : NSObject
#property (nonatomic, strong) Prot1 *delegate;
- (void)methodInClass;
#end
The implementation for this class is like this:
#import "Class1.h"
#import "Prot1.h"
#implementation Class1
#synthesize delegate;
- (void)methodInClass {
[delegate methodInProt];
}
#end
When I build these pieces of code, I get the following error:
Receiver type 'Prot1' for instance message is a forward declaration
What is wrong here? I did understand that I have to do a forward declaration via #class for the protocol and I thought I only had to #import the protocol, in the class implementation... Isn't that right?
As it isnt a class, you have to define it as what it is - a protocol ;)
Use forward declaration: #protocol Prot1;;
And use the property like that:
#property (nonatomic, strong) id<Prot1> delegate;

Is it possible to declare a second #interface for a category?

I am trying to declare a private #interface for a category, in the .m file.
For a normal class I would do:
#interface ClassA ()
#end
#implementation ClassA
#end
and it would work smoothly.
For a class with categories I tried:
#interface ClassA (CategoryA) ()
#end
#implementation ClassA (CategoryA)
#end
but it is giving all sort of different errors. I am trying to "extend" a category, the way that a class is extended via this syntax #interface ClassA ().
I want to have private methods for the category, and I wanted to know if, IN ADDITION to the exposed interface I am allowed to put a second category #interface in the .m file, which does not expose instance variables and methods outside the class itself.
Something like this:
ClassA+categoryA.h
#interface ClassA (CategoryA)
<some public methods>
#end
ClassA+categoryA.m file
#interface ClassA (CategoryA)
<some private methods>
#end
#implementation ClassA (CategoryA)
<here I want to be able to call the private methods above>
#end
Right now this is giving me a warning in Xcode:
Duplicate definition of category 'CategoryA' on interface 'ClassA'
Is there any way to get this behavior?
No, you can't declare two interfaces for a single category. You can do one of two things:
Englebert+Humperdinck.h
#import "Englebert.h"
#interface Englebert (Humperdinck)
- (void) croon;
#end
You can declare another category with a different name to contain the private methods. These can then be used in the same file where the private category interface is declared:
Englebert+Humperdinck.m
#import "Englebert+Humperdinck.h"
#interface Englebert (HumperdinckPrivate)
- (void) warmUp;
#end
#implementation Englebert (HumperdinckPrivate)
- (void)warmUp {
NSLog(#"Warm up");
}
#end
#implementation Englebert (Humperdinck)
- (void)croon {
[self warmUp];
NSLog(#"Croon");
// etc.
}
#end
The other option is to simply not declare the private methods. If you just define them in the implementation block, you can use them at any point in that file after they are defined (and for the latest version of Xcode/LLVM, the order is in fact unimportant -- undeclared methods can be used anywhere in the file in which they are defined). No other files will be able to see these methods.
Englebert+Humperdinck.m
#import "Englebert+Humperdinck.h"
#implementation Englebert (Humperdinck)
/* Undeclared private method */
- (void)warmUp {
NSLog(#"Warm up");
}
- (void)croon {
[self warmUp];
NSLog(#"Croon");
// etc.
}
#end
Do
#interface ClassA (CategoryA)
#end
#implementation ClassA (CategoryA)
#end
Instead. Categories can't have instance varibles. And what kind of errors are you talking about?
#interface ClassA () is an anonymous category, and you can use these as interfaces and define the implementation in the ClassA implementation as well. #interface ClassA (CategoryA) () is a syntax error and should read #interface ClassA (CategoryA)
EDIT:
To create private methods for a class, in that class' .m file you would have:
#interface ClassA ()
// Private functions declared
#end
#implementation ClassA
// Private functions defined
// Other functions defined
#end
The same can be done for named categories, however you will need to define the implementation separately to avoid warnings. Again, in the .m file:
#interface ClassA (hidden)
// Private functions declared
#end
#implementation ClassA (hidden)
// Private functions declared
#end
#implementation ClassA
// Other functions defined
#end