Can i use two delegates: delegateA in classB, delegateB in classA? - objective-c

i've got my code in HelloWorldLayer, i'm using a delegate to change the score number in ScoreLayer, and i would like to send a message back from ScoreLayer to HelloWorldLayer, in order to change the ui with a new image.
Is it ok to create a delegate in each class (one delegate of HelloW... in ScoreLayer, and one delegate of ScoreLayer in HelloW...) ? Something like that :
hellolayer.delegate = scoreLayer;
scoreLayer.powerUpDelegate = hellolayer;
?
#class MyClass does not work : the protocols are not being recognized.
"#import "..." : one of the protocol is not recognized, but i guess there will be a problem, as classA will import classB, which will import classA again etc.
How should i do? Here's some of the code :
//in HelloWorldLayer.h :
#import "ScoreLayer.h"
#protocol PowerUpDelegate
-(void)scalePowerUp;
#end
// HelloWorldLayer
#interface HelloWorldLayer : CCLayer <PowerUpDelegate>
{ … }
#property (nonatomic,retain) id <ScoreDelegate> delegate;
//in ScoreLayer.h :
//#class HelloWorldLayer; -->does not recognize the protocol
#import "HelloWorldLayer.h"
#protocol ScoreDelegate
//...
#end
#interface ScoreLayer : CCLayer <ScoreDelegate>{
//...
}
#property (nonatomic,retain) id <PowerUpDelegate> powerUpDelegate;//-->cannot find protocol definition...
Thanks

I recommend using a third class which implements both protocols and use that class to handle the delegate methods.

Yes; you can pre-declare the protocols like you pre-declare classes, so put this at the top of your ScoreLayer class:
#protocol PowerUpDelegate;

Related

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

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.

do you need to import .h files when using delegates?

-(IBAction)ok
{
//send message to the delegate with the new settings
[self.delegate setHeight:_height Width:_width Mines:_mines];
[self.delegate dismissViewControllerAnimated:YES completion:nil];
}
the first message to the delegate wouldn't work until i imported ViewController.h, but the second one worked without the import.
if i add -(void)setHeight:(int)h Width:(int)w Mines:(int)m; as required in the optionsViewController protocol will that mean that i no longer have to import the root .h file.
i intend to use delegation to send messages in other parts of the program so i want to make sure i am using it correctly and not importing things when i don't need to.
Thank you.
if i add -(void)setHeight:(int)h Width:(int)w Mines:(int)m; as required in the optionsViewController protocol will that mean that i no longer have to import the root .h file.
Yes! You could also add it as #optional and it would work (remember to check if the delegate -respondsToSelector: in that case). The whole idea is that your object regularly knows nothing about the delegate object - except that it conforms to the protocol (ie implements the #required and possibly the #optional methods).
Added for clarification (on my phone, which is a pain in the butt):
//OptionsViewController.h
//this object does NOT have to import
//the calling viewControllers .h file
//which is what I think the OP does
#protocol optionsViewControllerProtocol;
#interface OptionsViewController : UIViewController
#property (nonatomic, assign) id<optionsViewControllerProtocol> delegate; //should be id, could be UIViewController too, if absolutely necessary (better design to make it id)
#end
#protocol optionsViewControllerProtocol <NSObject>
#required
-(void) setHeight: (NSInteger) height;
#end
//viewController.h
#import "optionsViewController.h" //necessary to get the protocols definitions
#interface OptionsViewController: UIViewController <optionsViewControllerProtocol>
//.....
If you define your delegate property to be of class UIViewController*, then the compiler will recognize the dismissViewControllerAnimated:completion: method without you needing to import anything, since that's a standard method for that class.
For a custom method, i.e. setHeight:Width:Mines:, you absolutely need to import the header file, or have it imported somewhere up the import chain.
Example: You have MyProtocol.h, and you want SomeClass to have a delegate property that conforms to that protocol. If you #import "MyProtocol.h" in SomeClass.h, you don't need to re-import it in SomeClass.m.
// SomeClass.h
#import "MyProtocol.h"
#interface SomeClass : NSObject
#property (weak, nonatomic) id<MyProtocol> delegate;
#end
//SomeClass.m
#import "SomeClass.h"
#implementation SomeClass
- (void)someMethod
{
[self.delegate myProtocolMethod];
}
#end

Move Delegates to their own classes?

My view controller is getting a little large for me. I'm implementing five delegate protocols and was about to add a sixth.
ABCViewController : UITableViewController<NSFetchedResultsControllerDelegate,
UITableViewDelegate,
UITableViewDataSource,
UIAlertViewDelegate,
CLLocationManagerDelegate>
One controller to implement them all seems ridiculous, but they aren't being used anywhere else. Should these be in their own classes or in the view controller?
You could add categories to ABCViewController, like this:
1. Move any declarations in ABCViewController.m into a private category in ABCViewController.h
// in ABCViewController.h
#interface ABCViewController : UIViewController <delegates>
// anything that's in the _public_ interface of this class.
#end
#interface ABCViewController ()
// anything that's _private_ to this class. Anything you had defined in the .m previously
#end
2. ABCViewController.m should include that .h.
3. Then in ABCViewController+SomeDelegate.h and .m
// in ABCViewController+SomeDelegate.h
#interface ABCViewController (SomeDelegateMethods)
#end
// in ABCViewController+SomeDelegate.m
#import "ABCViewController+SomeDelegate.h"
#import "ABCViewController.h" // here's how will get access to the private implementation, like the _fetchedResultsController
#implementation ABCViewController (SomeDelegateMethods)
// yada yada
#end
You can also declare conformity to that protocol in the .m file like this:
#interface ABCViewController (NSFetchedResultsControllerDelegateMethods) <NSFetchedResultsControllerDelegate>
#end
#implementation ABCViewController (NSFetchedResultsControllerDelegateMethods)
...
#end
This won't make your file shorter but at least it will be clearly divided into parts
If you are using Xcode you can try something like this for example:
#pragma mark - NSFetchedResultsControllerDelegateMethods
Quite handy to find your methods like in this tip: Pragma mark
Alternatively, depending on what you do the delegate methods and how structured is your code you could have another object that has only methods of the delegate protocol
#interface Delegate <NSFetchedResultsControllerDelegate> : NSObject
#end
You would have an instance of this object as an ivar in your ABCViewController.

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.