Declaring delegate protocol in the same file - ios

I have following header:
#protocol AttachmentsViewDelegate <NSObject>
#required
- (void)spaceRequestedWithSize:(CGSize)size sender:(AttachmentsView*)sender;
#end
#interface AttachmentsView : UIView
#property id<AttachmentsViewDelegate> delegate;
#property NSArray *attachments;
- (void)takePicture;
- (void)deletePictures;
#end
Doesn't work because inside #protocol I reference to AttachmentsView and it's not declared yet.
If I move #protocol below #interface - I have another problem, because delegate property doesn't know about #protocol.
I know I can use id, UIView for types, but to keep it "strongly typed", what can I do? I really prefer not to break it down into 2 files. Any other options/suggestions?

Use #class to forward-declare AttachmentsView like so:
#class AttachmentsView;
#protocol AttachmentsViewDelegate <NSObject>
// Protocol method declarations...
#end
Alternatively, use #protocol to forward-declare the protocol:
#protocol AttachementsViewDelegate
#interface AttachmentsView : UIView
// Ivar, method, and property declarations...
#property id<AttachmentsViewDelegate> delegate;
#end

just write:
#class AttachmentsView;
on top of the file.
In case you wish to declare the class first, and then the protocol, write first:
#protocol AttachmentsViewDelegate;
on top of the file.

Related

pass delegating object type as protocol method argument

I want to pass my delegating object as an argument with a declared type so I don't have to cast (if I pass (id)sender instead):
#protocol myObjectDelegate <NSObject>
- (void)myObjectAsArgument:(myObject *)object;
#end
#interface myObject : NSObject
// stuff...
#property (nonatomic, strong) id <myObjectDelegate> delegate;
#end
What would be the correct way of doing this? Like I said, I know I could do this:
- (void)myObjectAsArgument:(id)object;
And that would let me pass self in as argument, but I don't like using the cast syntax.
Thanks.
NOTE:
Apple does that too:
#protocol UITableViewDataSource <NSObject>
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
#end
#interface UITableView : UIScrollView
#property (nonatomic, strong) id <UITableViewDataSource> dataSource;
#end
That's just one method from the UITableViewDataSource protocol and it's passing a UITableView type as argument. ;)
Since this is top Google search result, here's how to do it:
#class myObject; // just need this for compiling
#protocol myObjectDelegate <NSObject>
- (void)myObjectAsArgument:(myObject *)object;
#end
#interface myObject : NSObject
// stuff...
#property (nonatomic, strong) id <myObjectDelegate> delegate;
#end
You should do it this way:
- (void)myObjectAsArgument:(id<myObjectDelegate>)object;
with myObjectDelegate being the name of your protocol ;)

Custom Delegate cannot find declaration

I'm creating a shopping list app, and trying to implement a custom delegate when editing an item. When creating the #protocol at the bottom of the header file, when trying to declare a property of that protocol in the #interface section I'm getting an error of: Cannot find protocol declaration for GEMEditItemViewControllerDelegate
This is what my header file looks like.
#import <UIKit/UIKit.h>
#import "GEMItem.h"
#interface GEMEditItemViewController : UIViewController <UIPickerViewDataSource, UIPickerViewDelegate>
#property GEMItem *item;
#property (weak) id<GEMEditItemViewControllerDelegate> delegate;
#end
#protocol GEMEditItemViewControllerDelegate <NSObject>
#required
- (void)controller:(GEMEditItemViewController *)controller didUpdateItem:(GEMItem *)item;
#end // End of delegate protocol
Alternatively in a separate instance when declaring the protocol above the interface I cannot access the view controller to pass as a parameter for that declaration method.
That header file looks like:
#import <UIKit/UIKit.h>
#import "GEMItemManager.h"
#protocol GEMAddItemViewControllerDelegate <NSObject>
/*
// Tried to add the controller (controller:(GEMAddItemviewController *)controller) as first paramiter, but was getting and errror, so I have omitted it for the time being
- (void)controller:(GEMAddItemViewController *)controller didSaveItemWithName:(NSString *)name andQuantity:(float)quantity andPrice:(float)price andCategory:(NSString *)category andNotes:(NSString *)notes;
*/
- (void)didSaveItemWithName:(NSString *)name andQuantity:(float)quantity andPrice:(float)price andCategory:(NSString *)category andNotes:(NSString *)notes;
#end
#interface GEMAddItemViewController : UIViewController <UIPickerViewDataSource, UIPickerViewDelegate>
#property (weak) id<GEMAddItemViewControllerDelegate> delegate;
#property NSArray *categories;
#end
Any thoughts on how to correct this would be greatly appreciated!!
You can do it like this also
#protocol GEMEditItemViewControllerDelegate;
#interface GEMEditItemViewController : UIViewController <UIPickerViewDataSource, UIPickerViewDelegate>
#property GEMItem *item;
#property (weak) id<GEMEditItemViewControllerDelegate> delegate;
#end
#protocol GEMEditItemViewControllerDelegate <NSObject>
#required
- (void)controller:(GEMEditItemViewController *)controller didUpdateItem:(GEMItem *)item;
#end
Try it this way:
#class GEMEditItemViewController; // forward declaration of class
#protocol GEMEditItemViewControllerDelegate <NSObject>
#required
- (void)controller:(GEMEditItemViewController *)controller didUpdateItem:(GEMItem *)item;
#end // End of delegate protocol
#interface GEMEditItemViewController : UIViewController <UIPickerViewDataSource, UIPickerViewDelegate>
#property GEMItem *item;
#property (weak) id<GEMEditItemViewControllerDelegate> delegate;
#end
BTW - you should move the two picker view protocols from the header file to a class extension in the .m file. The world doesn't need to know this implementation detail.
Your header file should looks like this:
#class GEMEditItemViewController;
#class GEMItem;
#protocol GEMEditItemViewControllerDelegate <NSObject>
#required
- (void)controller:(GEMEditItemViewController *)controller didUpdateItem:(GEMItem *)item;
#end // End of delegate protocol
#interface GEMEditItemViewController : UIViewController <UIPickerViewDataSource, UIPickerViewDelegate>
#property GEMItem *item;
#property (weak) id<GEMEditItemViewControllerDelegate> delegate;
#end
You should not use direct import in your header file. #class directive is used to prevent cycle dependencies. In your case GEMItem import should be in your meta file.

Forward declaration issue - ARC refactor

I am running an ARC 'refactor' on an old iOS app.
However, I am getting the following error
Receiver type 'WarningCallback' for instance message is a forward declaration
WarningCallback.h
#class WarningCallback;
#import <UIKit/UIKit.h>
#import "WebViewController.h"
#import "Constants.h"
#protocol WarningCallback
-(void) warningDismissedAndNavigateToCall:(BOOL) navigateToCall;
#end
#interface WarningViewController : WebViewController {
}
#property (nonatomic,retain) WarningCallback* parentVC;
#end
WarningCallback.m
#import "WarningViewController.h"
#implementation WarningViewController
#synthesize parentVC;
...
-(IBAction) done:(id) sender {
[[self parentVC] warningDismissedAndNavigateToCall:NO];
}
#end
The error occurs on the following line of WarningCallback.m
[[self parentVC] warningDismissedAndNavigateToCall:NO];
The error is because of the line #class WarningCallback;. The error message means that the compiler found a forward declaration of WarningCallback, but is not able to find the corresponding implementation. That's because WarningCallback is not a class, but a protocol.
If you want to forward declare a protocol you can do so as follows:
#protocol WarningCallback;
#interface WarningViewController : WebViewController
#property (nonatomic, weak) id<WarningCallback> parentVC;
#end
#protocol WarningCallback
- (void)warningDismissedAndNavigateToCall:(BOOL) navigateToCall;
#end
Note how I've declared parentVC.
Remove the line:
#class WarningCallback;
When declaring a #protocol, it is not necessary to also declare it as a #class unless you have a specific reason to do so. See:
What's with the declare a class and declare a protocol with the same name?

How to create delegation from child to parent (subview-superview)

i've worked with delegation before. i know how to create delegation from a superview to a subview class. however, i'm trying to do it the opposite way using the same approach but it's not working! is delegation meant only to work one way or is there a way/trick to use it as a two way communication between the classes? I'm receiving an error at the parent/superview .h class which is:
Cannot find protocol definition for 'SubViewControllerDelegate'
my code goes like this:
subview.h
#import <UIKit/UIKit.h>
#import "SuperViewController.h"
#protocol SubViewControllerDelegate <NSObject>
- (void)someMethod:(NSData *)data;
#end
#interface SubViewController : UIViewController
#property (weak, nonatomic) id <SubViewControllerDelegate> delegate;
#end
subview.m:
[self.delegate someMethod:data];
SuperView.h
#import <UIKit/UIKit.h>
#import "SubViewController.h"
#interface SuperViewController : UIViewController <SubViewControllerDelegate>
#end
SuperView.m:
#pragma mark - SubView Controller Delegate Methods
- (void)someMethod:(NSData *)data{
NSLog(#"%#", data);
}
am i doing anything wrong or missing out anything?
You have an "import-cycle", because "SuperViewController.h" imports "SubViewController.h" and vice versa.
Removing the #import "SuperViewController.h" in "SubViewController.h"
should solve the problem.
If you really need that class to be declared in "SubViewController.h", use
#class SuperViewController; to avoid the import-cycle.
Remark: The <SubViewControllerDelegate> protocol declaration is probably not
needed in the public interface "SuperViewController.h" at all.
In "SuperViewController.h", declare the class as
#interface SuperViewController : UIViewController
In "SuperViewController.m", define a class extension with the protocol:
#interface SuperViewController () <SubViewControllerDelegate>
#end

Having an ivar 'delegate' in a subclass whose superclass also has same named ivar

I have a subclass defined like this
#protocol UMTextViewDelegate;
#interface UMTexView : UITextView <UITextViewDelegate> {
}
#property (nonatomic, assign) id<UMTextViewDelegate> delegate;
#end
#protocol UMTextViewDelegate <NSObject>
#optional
- (void)textViewDidSelectWordToDefine:(UMTexView*)textView;
#end
But I get a warning Property type 'id<UMTextViewDelegate>' is incompatible with type 'id<UITextViewDelegate>' inherited from 'UITextView'.
How do I suppress this warning ? I tried adding this :
#protocol UMTextViewDelegate <NSObject, UITextViewDelegate>
but no luck. !!
EDIT:
I am not using ARC
The problem you are having is about forward declarations. In the place where you are declaring the delegate, the compiler doesn't know that UMTextViewDelegate descends from UITextViewDelegate. The only thing it knows is that UMTextViewDelegate is a protocol.
You have to create a forward declaration for the class #class UMTexView;, then put the protocol declaration and then the class declaration.
On a separate note, it's obvious UMTexView is supposed to be the text delegate for itself. Maybe it would be easier to have UMTexView descending directly from UIView and put an UITextView inside it. Then you wouldn't have any problem with delegate collisions and the UITextViewDelegate would be unaccessible externally.
Using #Sulthan's answer, this is what I came up with and it squished the warning.
#class UMTextView;
#protocol UMTextViewDelegate <NSObject, UITextViewDelegate>
#optional
- (void)textViewDidSelectWordToDefine:(UMTextView*)textView;
#end
#interface UMTextView : UITextView <UITextViewDelegate>
#property (nonatomic, assign) id<UMTextViewDelegate> delegate;
#end
The forward declaration of UMTextView followed by protocol declaration tells UMTextView that UMTextViewDelegate is indeed descends from UITextViewDelegate. That way I don't have to the route of adding a uiview and then adding a uitextview inside that view.

Resources