I have a little problem; I have this protocol defined as so below:
#protocol someProtocol <NSObject>
- (void) changedStoryForIndexPath: (NSIndexPath *) indexPath;
#end
I have it defined in a file named "ListViewController.h", logically I have to import the header in another file like: #import "ListViewController.h" then in my #interface declare the protocol in the protocol tags like <someProtocol> right? When do I do so then compile, the compiler (on Xcode 4.0 and 3.2.4) tells me that it can't find the protocol declaration. You can see the error here: http://www.freeimagehosting.net/uploads/5ff0c99bf7.png
Thank You guys!
You should have the protocol in a different header file.
SomeProtocol.h:
#protocol someProtocol <NSObject>
- (void) changedStoryForIndexPath: (NSIndexPath *) indexPath;
#end
And import it in the ListViewController class.
#import "SomeProtocol.h"
Related
How would I use the class that the delegate is for inside of the protocol methods.
Ex:
#protocol ILMIconDelegate <NSObject>
- (void)deleteIcon:(ILMIcon *)icon;
#end
#interface ILMIcon : UIView <IconPopoverViewControllerDelegate>
...
#end
This doesn't work because I can't use (ILMIcon *) inside the protocol as it's declared later in the file.
Any help?
Is there any work around, or should I just use (UIView *) instead?
Thanks
Edit: newacct gave me the answer of using #class ILMIcon; before the protocol and it works!
Thanks alot man!
You can forward-declare the class before the protocol declaration, like:
#class ILMIcon;
I have two objects, both of which are view controllers. The first (Ill call it viewController1) declares a protocol. The second (which unsurprisingly I will name viewController2) conforms to this protocol.
XCode is giving me a build error of: 'Cannot find protocol declaration for viewController1'
I have seen various questions on this subject and I am certain it is to do with a loop error, but I just can't see it in my case...
Code below..
viewController1.h
#protocol viewController1Delegate;
#import "viewController2.h"
#interface viewController1 {
}
#end
#protocol viewController1Delegate <NSObject>
// Some methods
#end
viewController2.h
#import "viewController1.h"
#interface viewController2 <viewController1Delegate> {
}
#end
Initially, I had the import line in viewController1 above that of the protocol declaration. This was preventing the project from building at all. After searching on SO, I realised the problem and switched the two lines around. I am now getting a warning (as opposed to an error). The project builds fine and actually runs perfectly. But I still feel there must be something wrong to be given a warning.
Now, as far as I can see, when the compiler gets to viewController1.h, the first thing it sees is the declaration of the protocol. It then imports the viewController.h file and sees this implements this protocol.
If it were compiling them the other way around, it would look at viewController2.h first, and the first thing it would do is import viewController1.h the first line of which is the protocol declaration.
Am I missing something?
Remove this line from viewController1.h:
#import "viewController2.h"
The problem is that viewController2's interface is preprocessed before the protocol declaration.
The general structure of the file should be like this:
#protocol viewController1Delegate;
#class viewController2;
#interface viewController1
#end
#protocol viewController1Delegate <NSObject>
#end
A.h:
#import "B.h" // A
#class A;
#protocol Delegate_A
(method....)
#end
#interface ViewController : A
#property(nonatomic,strong)id<ViewControllerDelegate> preViewController_B;(protocol A)
#end
B.h:
#import "A.h" // A
#class B;
#protocol Delegate_B
(method....)
#end
#interface ViewController : B
#property(nonatomic,strong)id<ViewControllerDelegate> preViewController_A;(protocol B)
#end
A.m:
#interface A ()<preViewController_B>
#end
#implementation A
(implement protocol....)
end
B.m:
#interface B ()<preViewController_A>
#end
#implementation B
(implement protocol....)
#end
For those who might need it:
It's also possible to fix this by moving the importation of ViewController1.h in ViewController2's implementation file (.m) instead of the header file (.h).
Like so:
ViewController1.h
#import ViewController2.h
#interface ViewController1 : UIViewController <ViewController2Delegate>
#end
ViewController2.h
#protocol ViewController2Delegate;
#interface ViewController2
#end
ViewController2.m
#import ViewController2.h
#import ViewController1.h
#implementation ViewController2
#end
This will fix the case where the error happens because ViewController1.h is imported in ViewController2.h before the protocol declaration.
(I found some questions discussing the idea, but I didn't see a solution for my problem.)
I added this convenience method as a category to NSObject. (I've added other methods, so I'm still interested in an answer even if you disagree with this particular convenience method.)
#implementation NSObject (MyCategory)
- (void)performInvocationOnMainThread:(NSInvocation *)invocation waitUntilDone:(BOOL)waitForMainThread;
#end
Then I have a protocol I defined:
#protocol MyDelegateProtocol <NSObject>
- (void)myDelegateProtocolMethod;
#end
Then I declare the delegate as a property of my class that implements said protocol.
#property (nonatomic, assign) id <MyDelegateProtocol> delegate;
But when I try to call the NSObject method I added in my category like so
NSInvocation *invocation = [self.delegate invocationForSelector:#selector(someSelector:withArg:)];
I get this warning
'-performInvocationOnMainThread:waitUntilDone:' not found in protocol(s)
If I cast my delegate as (NSObject *) then I don't get the warning. What am I doing wrong? It didn't seem like I could (or should?) add methods to an existing protocol without creating a "sub protocol" and using it from then on. (Which kind of defeats the point of adding methods to NSObject in mind.)
NSInvocation *invocation = [(NSObject *)self.delegate invocationForSelector:#selector(someSelector:withArg:)];
Your category extends the NSObject class, not the NSObject protocol. While the class now has the method, it's not defined as part of the protocol, hence the warning.
That's why typecasting to the NSObject * pointer type works; you're casting to the NSObject class type, rather than something like id<NSObject> which means an arbitrary Objective-C object that conforms to the NSObject protocol.
You'll have to make an intermediate protocol (or "sub protocol") that extends the NSObject protocol:
#protocol ExtendedNSObject <NSObject>
- (void)performInvocationOnMainThread:(NSInvocation *)invocation waitUntilDone:(BOOL)waitForMainThread;
#end
Then have your delegate protocol extend that one instead:
#protocol MyDelegateProtocol <ExtendedNSObject>
- (void)myDelegateProtocolMethod;
#end
If I'm not wrong, you can keep the existing NSObject (MyCategory) implementation, and they'll play nice together.
when pass/expect this type, qualify it like so:
- (void)race:(NSObject<MyDelegateProtocol>*)arg;
I am writing my first lines in objective-c for an iPhone app.
This is the code:
/* ViewController.h */
#protocol ImageFlowScrollViewDelegate;
#interface ViewController : UIViewController<ImageFlowScrollViewDelegate> {
NSMutableArray *characters;
UILabel *actorName;
}
/* ViewController.m */
#import "ImageFlowScrollView.h"
#implementation IMDBViewController
/* methods here */
/* ImageFlowScrollView.h */
#protocol ImageFlowScrollViewDelegate;
#interface ImageFlowScrollView : UIScrollView<UIScrollViewDelegate> {
NSMutableArray *buttonsArray;
id<ImageFlowScrollViewDelegate> imageFlowScrollViewDelegate;
}
#property(nonatomic, assign)id<ImageFlowScrollViewDelegate> imageFlowScrollViewDelegate;
- (id)initWithFrame:(CGRect)frame imageArray:(NSArray *) anArray;
- (void)focusImageAtIndex:(NSInteger) index;
#end
#protocol ImageFlowScrollViewDelegate<NSObject>
#optional
- (void)imageFlow:(ImageFlowScrollView *)sender didFocusObjectAtIndex: (NSInteger) index;
- (void)imageFlow:(ImageFlowScrollView *)sender didSelectObjectAtIndex: (NSInteger) index;
#end
Doing this, I get a
warning: no definition of protocol
'ImageFlowScrollViewDelegate' is found
I can fix it using:
#import "ImageFlowScrollView.h"
#interface IMDBViewController : UIViewController<ImageFlowScrollViewDelegate> {
NSMutableArray *characters;
UILabel *actorName;
}
but I would like to know why the forward declaration approach is giving me a warning.
The forward declaration defines the symbol so the parser can accept it. But when you try to use the protocol (or class) - as you do by conforming to the protocol - the compiler needs it's definition to know the layout and size of the resulting object.
In addition, you can forward a class or protocol when you are only using it in the class (in an ivar for example). The compiler then only needs to know the existence of the symbol. But when making use of the class (in the implementation file), the methods need to be declared before use hence the need to include the declaration.
For example :
/* AViewController.h */
#class AnotherClass;
#interface AViewController : UIViewController {
AnotherClass* aClass; //only need the declaration of the name
}
#end
/* AViewController.m */
#import "AnotherClass.h"
#implementation AViewController
- (void) useAnotherClass {
[AnotherClass aMessage]; //aMessage needs to be declared somewhere, hence the import
}
#end
In addition, you already know that you must provide actual implementations in order to link your program.
I have a large class, which I have divided into several different class extension files for readability.
#protocol MyProtocol
#required
-(void)required;
#end
#interface MyClass : NSObject <MyProtocol>
#end
#interface MyClass (RequiredExtension)
-(void)required;
#end
Is there a better way to do this, without the compiler warning?
warning: class 'MyClass' does not fully implement the 'MyProtocol' protocol
Use a category for each protocol implementation. I use this when I have complex viewControllers.
For example, I have a category that implements NSTextDelegate protocol.
So, MyComplexViewController+NSTextDelegate.h:
#import "MyComplexViewController.h"
#interface MyComplexViewController (NSTextDelegate) <NSTextDelegate>
#end
and MyComplexViewController+NSTextDelegate.m:
#import "MyComplexViewController+NSTextDelegate.h"
#implementation MyComplexViewController (NSTextDelegate)
- (BOOL)textShouldBeginEditing:(NSText *)textObject{
...
}
- (BOOL)textShouldEndEditing:(NSText *)textObject{
...
}
- (void)textDidBeginEditing:(NSNotification *)notification{
...
}
- (void)textDidEndEditing:(NSNotification *)notification{
...
}
- (void)textDidChange:(NSNotification *)notification{
....
}
#end
Then I take all the headers for the main class definition and the categories and combine them into one header which I then import where I need to use the class.
#interface MyClass : NSObject
#end
#interface MyClass (RequiredExtension) <MyProtocol>
-(void)required;
#end
Adopt the protocol in the category.
You don't need to change your style of coding. To get around the warning, it only need to implement "required" method of the protocol, not "optional"
If that's only for readability, you should use categories only. A protocol is not needed in such a case.