Welcome to the Treehouse Community
Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.
Looking to learn something new?
Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.
Start your free trial
kennedy otis
3,570 PointsDelegation in ios
Hi guys Am trying to implement some protocols but I keep on getting "Can not find protocol MainViewControllerDelegate".. I have two view controllers namely MainViewController and MusicViewController.
In the MusicViewController.. I have declared a delegate which gets the selected row info and pass that info to MainViewController since it implements that delegate. This is how my MusicViewController delegate looks like...
//MusicViewController.h
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
@protocol musicViewControllerDelegate;
@protocol musicViewControllerDelegate <NSObject>
-(void)playSelectedMusic:(NSString *)music andArtist:(NSString *)artist andTitle:(NSString *)title;
@end
@interface MusicViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
@property (nonatomic,weak) id<musicViewControllerDelegate> delegate;
While in my MainViewController I have another protocol like so:
#import "MusicViewController.h"
@protocol MainViewControllerDelegate;
@protocol MainViewControllerDelegate <NSObject>
-(void)showCurrentPlayingMusic:(NSString *)title;
@end
@interface MainViewController : UIViewController <UIScrollViewDelegate,musicViewControllerDelegate>
So far I do not get any compiler error and it works fine. Issue now comes when I want to use MainViewController protocol in MusicViewController class.
I have tried to import MainViewController.h in my MusicViewController class so that I can get a chance of implementing the its protocols but I keep on getting error "Can not find protocol MainViewControllerDelegate"...
This is how I tried to make use of MainViewController protocol in MusicViewController..
//MusicViewController.h
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#import "MainViewController.h"
@protocol musicViewControllerDelegate;
@protocol musicViewControllerDelegate <NSObject>
-(void)playSelectedMusic:(NSString *)music andArtist:(NSString *)artist andTitle:(NSString *)title;
@end
@interface MusicViewController : UIViewController <UITableViewDataSource, UITableViewDelegate,MainViewControllerDelegate>
So the error comes when I import #import "MainViewController.h" and trying include MainViewControllerDelegate as shown above..
Any help?
8 Answers
Jesus Guerra Rosas
3,287 PointsHi Kennedy,
The issue could be due the circulare reference that you have on MainViewController you are importing MusicViewController.h and in MusicViewController you are importing MainViewController.h. Try using @class instead #import, @class helps to circular reference.
Let me know if that works.
Also I let me suggest you, in your protocol method in musicViewControllerDelegate instead passing 3 parameters you could pass a object lest say "PlayingSong" as properties it will have music, artist and title in that way if you need to add more data you only add it to the model instead to stack more parameter to your delegate method.
kennedy otis
3,570 PointsHi. Thanks for taking time to go through my problem.. However I have tried to use @class instead and I keep on getting the same error.. I have to include @class MainViewController; In the MusicViewController class so that I can be able to implement MainViewController's delegate but I keeps on throwing an error saying MainViewControllerDelegate can not be found.
Thomas Nilsen
14,957 Points@protocol musicViewControllerDelegate;
@protocol musicViewControllerDelegate <NSObject>
-(void)playSelectedMusic:(NSString *)music andArtist:(NSString *)artist andTitle:(NSString *)title;
@end
The first @protocol line can you remove from both viewControllers. There is no need for that
Also, It is customary for the delegate methods to have a reference to their owner as the first (or only) parameter, so call it:
-(void) musicViewController:(MusicViewController *)controller playSelectedMusic:(NSString *)music andArtist:(NSString *)artist andTitle:(NSString *)title;
When you write it like this, also remember to put
@class <yourViewController>
Before you declare the protocol
kennedy otis
3,570 PointsHi I have tried that and now there is no error but I can not implement the MainViewControllerDelegate in my MusicViewController class.. Also when one use @class , should the import of that class be removed?
Thomas Nilsen
14,957 PointsI shouldn't make any difference wether you have both or just one. But when you "I can not implement the MainViewControllerDelegate in my MusicViewController class.. ". What exactly is going wrong?
Here is a detailed description between class and import of .h file
-
The line @class <you class> simply says to the compiler: if you see the name <you class> then that’s an object we’re going to be using. It doesn’t tell the compiler exactly what that object does, just that it’s an object. You’ll use @class mostly in .h files because at that point the compiler doesn’t need to know what the object’s properties and methods are, just that it exists. This is also known as a forward declaration.
- #import "some class.h" literally adds the contents of the class file into the current file when it is being compiled. It means that when you use #import, the compiler knows everything about that object. If you want to access the properties of an object or call any of its methods, you need to use #import.
kennedy otis
3,570 PointsNow I get you clearly..thanks.. When I said "I can not implement the MainViewControllerDelegate in my MusicViewController class.. " its because I was expecting to make the MusicViewController class to conform the MainViewController.. And from the little knowledge about ios, that can be achieved by passing the name of the delegate in those <> of the class which you want to conform to the delegate. This is what I am trying to achieve.
//MusicViewController.h
@class MainViewController;
@protocol MusicViewControllerDelegate <NSObject>
-(void)playSelectedMusic:(Track *)track;
@end
@interface MusicViewController : UIViewController <UITableViewDataSource, UITableViewDelegate,MainViewControllerDelegate>
@property (nonatomic,weak) id<MusicViewControllerDelegate> delegate;
@end
But it says "Can not find protocol MainViewControllerDelegate"... It then offers suggestion of using "MusicViewControllerDelegate" which is not what I want.
Note: I removed the @protocol as you suggested and instead use @class.
//MainViewController.h
@class MainViewController;
@protocol MainViewControllerDelegate <NSObject>
-(void)showCurrentPlayingMusic:(NSString *)title;
@end
@interface MainViewController : UIViewController <UIScrollViewDelegate,MusicViewControllerDelegate>
@property (nonatomic,weak) id<MainViewControllerDelegate> delegate;
@end
Thomas Nilsen
14,957 PointsI'm pretty bad when it comes to explaining, so I'll tag Amit Bijlani here
kennedy otis
3,570 PointsNo.. you are doing good and I get you clearly.. I just don't get it why its not working... From those snippets.. Isn't that what you recommended I try? But you are a good teacher just for record. :)
Thomas Nilsen
14,957 PointsI made a simple delegate example on my own and that is working fine, So I'm having a bit of difficulty seeing where your problem is to be honest. The annoying thing is that it's probably the tiniest mistake
Amit Bijlani
Treehouse Guest TeacherThis discussion on Stack Overflow might help: http://stackoverflow.com/questions/13712943/forward-class-and-protocols-in-objective-c/13713973#13713973
Thomas Nilsen
14,957 Pointsaaaah WAIT.
In your musicViewController where you do this:
@interface MusicViewController : UIViewController <UITableViewDataSource, UITableViewDelegate,MainViewControllerDelegate>
@property (nonatomic,weak) id<MusicViewControllerDelegate> delegate;
@end
You DO need use the import statement at the top, NOT the @ class. Because like I wrote earlier, the class only tells the viewController an object is there. But when you want to implement it's methods, you need the import statement instead.
Same logic applies to the MainViewController when you implements the MusicViewController's delegate-methods.