Circular dependent methods in two different classes - objective-c

So I've been trying to organize my Objective-C code because as of now everything is in one huge file.
In a hypothetical situation:
Class A has methods "alertCompleted" and "prepareAlert".
Class B has a method "submitPost".
Let's say I'm in the A's method, "prepareAlert" from which I want to call B's method "submitPost". Then, from the "submitPost" method I need to call "alertCompleted" in A.
As you can see A calls methods in B and B calls methods in A. It's obviously ideal if I can have all the methods in the same class but I really need to organize my code (the methods above were just examples). How can I accomplish this? As far as I know categories only let the category class call the main class or vice verse but not both ways and importing each others headers gives me circular dependancy.

This is not really that big of a problem. You can use #class <classname> to create a forward.
ClassA.h
#class B;
#interface A : NSObject
- (void)needsB:(B *)b;
#end
ClassB.h
#class A;
#interface B : NSObject
- (void)needsA:(A *)a;
#end
It's in the .m file where you will need to import ClassA.h and ClassB.h

Here's One Way, although it feels a bit excessive:
ClassA.h
#import <Foundation/Foundation.h>
#import "ClassB.h"
#interface ClassA : NSObject
- (void) prepareAlert;
#end
ClassA.m
#implementation ClassA
- (void) prepareAlert {
NSLog(#"Class A: Preparing Alert");
ClassB * bClass = [ClassB new];
[bClass submitPostWithTarget:self andCallback:#selector(handleCompletion)];
}
- (void) handleCompletion {
NSLog(#"Class A: Handled Completion");
}
#end
ClassB.h
#import <Foundation/Foundation.h>
#interface ClassB : NSObject
- (void) submitPostWithTarget:(id)target andCallback:(SEL)callback;
#end
ClassB.m
#import "ClassB.h"
#implementation ClassB
- (void) submitPostWithTarget:(id)target andCallback:(SEL)callback {
NSLog(#"Class B: Submitting Post");
// Callback
IMP imp = [target methodForSelector:callback];
void (*func)(id, SEL) = (void *)imp;
func(target, callback);
}
#end
Then When I want to call it:
#import "ClassA.h"
And Run Like So:
ClassA * aClass = [ClassA new];
[aClass prepareAlert];
Will Print:
2014-03-14 20:25:05.207 MyApp[52877:60b] Class A: Preparing Alert
2014-03-14 20:25:05.208 MyApp[52877:60b] Class B: Submitting Post
2014-03-14 20:25:05.209 MyApp[52877:60b] Class A: Handled Completion
This way, if you have a specific instantiation of ClassA that you want called from within ClassB, it will still work.

Related

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.

Access ivar from subclass in Objective-C

I have class A which has this declaration in it's .m file:
#implementation A {
NSObject *trickyObject;
}
And class B which has this declaration in it's .h file:
#interface B : A
#end
Is there any possibility to access the trickyObject from a method declared in the class B?
If you have a property or method that is private, but you want to make accessible to subclasses, you can put the declaration in a category.
So consider A:
// A.h
#import Foundation;
#interface A : NSObject
// no properties exposed
#end
And
// A.m
#import "A.h"
// private extension to synthesize this property
#interface A ()
#property (nonatomic) NSInteger hiddenValue;
#end
// the implementation might initialize this property
#implementation A
- (id)init {
self = [super init];
if (self) {
_hiddenValue = 42;
}
return self;
}
#end
Then consider this category:
// A+Protected.h
#interface A (Protected)
#property (readonly, nonatomic) NSInteger hiddenValue;
#end
Note, this extension doesn’t synthesize the hiddenValue (the private extension in A does that). But this provides a mechanism for anyone who imports A+Protected.h to have access to this property. Now, in this example, while hiddenValue is really readwrite (as defined in the private extension within A), this category is exposing only the getter. (You obviously could omit readonly if you wanted it to expose both the getter and the setter, but I use this for illustrative purposes.)
Anyway, B can now do things like:
// B.h
#import "A.h"
#interface B : A
- (void)experiment;
// but again, no properties exposed
#end
And
// B.m
#import "B.h"
#import "A+Protected.h"
#implementation B
// but with this category, B now has read access to this `hiddenValue`
- (void)experiment {
NSLog(#"%ld", (long)self.hiddenValue);
}
#end
Now A isn’t exposing hiddenValue, but any code that uses this A (Protected) category (in this case, just B) can now access this property.
And so now you can call B methods that might be using the hiddenValue from A, while never exposing it in the public interfaces.
// ViewController.m
#import "ViewController.h"
#import "B.h"
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
B *b = [[B alloc] init];
[b experiment]; // this calls `B`’s exposed method, and that method is using the property not exposed by `A.h`
}
#end
If you’re interested in a real-world example of this, consider UIKit’s:
#import UIKit.UIGestureRecognizerSubclass;
Generally the state of a UIGestureRecognizer is readonly, but this UIGestureRecognizer (UIGestureRecognizerProtected) category exposes the readwrite accessors for state (to be used, as the name suggests, by gesture recognizer subclasses only).

Private methods in objective-c not private

I've created two classes with methods with same name. In one of them it is private, in another - public.
Then somewhere on code i write this:
-(void) doMagic:(id) object {
[(ClassA*)object doSmth];
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Insert code here to initialize your application
ClassB * objB = [[ClassB alloc] init];
[self doMagic:objB];
}
In console i see this:
2012-04-25 23:41:28.183 testmagic[558:403] classB - doSmth
Here's classes' sources:
//.h
#interface ClassA : NSObject
-(void) doSmth;
#end
//.m
#implementation ClassA
-(void)doSmth {
NSLog(#"classA - doSmth");
}
#end
//.h
#interface ClassB : NSObject
#end
//.m
#interface ClassB ()
-(void) doSmth;
#end;
#implementation ClassB
- (void)doSmth {
NSLog(#"classB - doSmth");
}
#end
I know, it's because of "message" nature of methods in Obj-C, and at runtime class possibly do not know which of it's methods are private or public, but here's the question:
How can i make really private method? I heard that with decompiling it's possible to see methods names, so someone can just use my private API. How can i prevent it?
The runtime cannot call what it never knows about. The approach I typically take is to use a static function:
MONObject.h
#interface MONObject : NSObject
// ...
#end
MONObject.m
// 'private' methods and ivars are also visible here
#interface MONObject()
// ...
#end
// typically here:
static void fn(MONObject * const self) {
NSLog(#"%#", [self description]);
}
#implementation MONObject
// ...
// sometimes here:
static void fn2(MONObject * const self) {
NSLog(#"%#", [self description]);
}
#end
A workaround to your problem could be to use a proxy/façade class which internally aggregates an instance of your private class. E.g.:
// .h
#interface FoobarFacade: NSObject
- (void)publicMethod;
#end
// .m
#interface FoobarFacade ()
{
Foobar* impl;
}
#end
#interface Foobar: NSObject
- (void)secretMethod;
#end
#implementation Foobar
- (void)secretMethod { NSLog(#"foobar secret method"); }
#end
#implementation FoobarFacade
- (void)publicMethod {
NSLog(#"façade public method");
[impl secretMethod]; // calling into the secret method
}
#end
Of course this isn't 100% safe either, the runtime puts no barriers as others already told.
Right now you can't have truly private methods. When you are declaring a method in a class extension in the .m file you are just hiding it from being exposed in the public header fle. What you are doing now is considered good design because you are hiding the method from the header file which means people would have to go to some length to find those hidden methods, but they can still find them.
Basically the rule I follow is to put as little as I can into the public header as possible and to put everything else into a class extension. This is all you can really do for now.
If you declare the method in the .h file is public. If you want private visibility you have to declare the method in your .m for example:
#interface ClassB (Private_Methods)
- (void)doSmth;
#end
#implementation ClassB
//Rest of .m

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

Reference properteries declared in a protocol and implemented in the anonymous category?

I have the following protocol:
#protocol MyProtocol
#property (nonatomic, retain) NSObject *myProtocolProperty;
-(void) myProtocolMethod;
#end
and I have the following class:
#interface MyClass : NSObject {
}
#end
I have a class extension declared, I have to redeclare my protocol properties here or else I can't implement them with the rest of my class.
#interface()<MyProtocol>
#property (nonatomic, retain) NSObject *myExtensionProperty;
/*
* This redeclaration is required or my #synthesize myProtocolProperty fails
*/
#property (nonatomic, retain) NSObject *myProtocolProperty;
- (void) myExtensionMethod;
#end
#implementation MyClass
#synthesize myProtocolProperty = _myProtocolProperty;
#synthesize myExtensionProperty = _myExtensionProperty;
- (void) myProtocolMethod {
}
- (void) myExtensionMethod {
}
- (void) useMyConsumer {
[[[MyConsumer new] autorelease] consumeMyClassWithMyProtocol:self];
}
#end
MyConsumer will only be called from MyClass, so I don't want any other classes to see that MyClass implements methods on MyProtocol because they aren't public API. Similarly, I don't want MyConsumer to see the class extension within MyClass.
#interface MyConsumer : NSObject {
}
#end
#implementation MyConsumer
- (void) consumeMyClassWithMyProtocol: (MyClass<MyProtocol> *) myClassWithMyProtocol {
myClassWithMyProtocol.myProtocolProperty; // works, yay!
[myClassWithMyProtocol myProtocolMethod]; // works, yay!
myClassWithMyProtocol.myExtensionProperty; // compiler error, yay!
[myClassWithMyProtocol myExtensionMethod]; // compiler warning, yay!
}
#end
Is there any way I can avoid redeclaring the properties in MyProtocol within my class extension in order to implement MyProtocol privately?
What you've been referring to as an "anonymous category" is actually known as a class extension, and is used to declare private functionality in an implementation file. That last part is important, because it means that other classes will not be able to see the declarations that you put into a class extension (and they won't be able to see that your class implements the methods of MyProtocol). This is also probably what is responsible for #synthesize failing without redeclaring the properties.
Instead, declare your conformance to the protocol in the interface of your class, and add whatever methods you want to be public:
#interface MyClass : NSObject <MyProtocol> {
}
// public methods and properties go here
#end
If you add the protocol declaration to your interface, then it also removes the need for your consumer to specify it explicitly. Your consumer method can have the following signature instead:
- (void) consumeMyClassWithMyProtocol: (MyClass *) myClassWithMyProtocol;
EDIT: It sounds like you're looking for a way to selectively expose private functionality. First, I would try to consider a different architecture for what you're trying to accomplish, because what's about to follow is a rather unpleasant solution, and it's generally better OOP if everything is public or private.
With that said, Apple typically solves this problem by having a separate header file for the class in question, which declares the methods that should be visible. So you would have your class interface, in which you expose everything that should be completely public:
// MyClass.h
#interface MyClass : NSObject {
}
#end
And a separate header, in which you declare a category for pseudo-private stuff:
// MyClass+Private.h
#import "MyClass.h"
#interface MyClass (Private) <MyProtocol>
- (void)mySortaPrivateMethod;
#end
MyClass.m would implement everything from those two files, and could still have a class extension:
// MyClass.m
#import "MyClass.h"
#import "MyClass+Private.h"
#interface MyClass ()
- (void)myClassExtensionMethod;
#end
#implementation MyClass
// everything can go here
#end
Then your consumer would include MyClass+Private.h so that it can see the declarations there, and everyone else would simply use MyClass.h.