Forward declaration issue - ARC refactor - ios

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?

Related

No type or protocol error while protocol is imported

At first, in LoadingVC.h I declare a protocol:
#protocol VideoWorker <NSObject>
#required
#property (nonatomic) float progress;
#property (nonatomic) BOOL done;
-(void)beginWorking;
#end
#interface LoadingVC : UIViewController <UIAlertViewDelegate>
...
#end
then in BlurWorkerGPU.h
...
#import "LoadingVC.h"
#interface BlurWorkerGPU : NSObject <VideoWorker> {
...
}
- (void)beginWorking;
#property(nonatomic)float progress;
#property(nonatomic)BOOL done;
...
#end
However, llvm says that
"No type or protocol named 'VideoWorker'"
which is strange since I am importing the header where the protocol is defined. Any clues?
You should forward declare protocol in .h files before you use it. Put this in the top of BlurWorkerGPU.h
#protocol VideoWorker;
check whether you are importing "BlurWorkerGPU.h" in "LoadingVC.h"
Possible solutions are
import protocol
#import
YOURPROTOCOLNAME
import Class in which protocol is declared
#import "YOURCLASSWHICHDECLAREDPROTOCOL.h"
Use #Class to import the class
#class YOURCLASSWHICHDECLAREDPROTOCOL;

Problems with adding a new delegate to a new controller

I am trying to figure out how to take the delegate in LocationViewController and SetScoringTableViewController and implement both of them in GameDetailsTableViewController. LocationViewControllerDelegate was already working, but when I added the new SetScoringTableViewController, the program had an error.
LocationViewController.h
#import "ViewController.h"
#class LocationViewController;
#protocol LocationViewControllerDelegate <NSObject>
- (void)addItemViewController:(LocationViewController *)controller didFinishEnteringItem:(NSString *)name;
#end
#interface LocationViewController : UIViewController
#property (nonatomic, weak) id <LocationViewControllerDelegate> delegate;
#end
SetScoringTableViewController.h
#import <UIKit/UIKit.h>
#import "GameDetailsTableViewController.h"
#import "LocationViewController.h"
#class SetScoringTableViewController;
#protocol SetScoringTableViewControllerDelegate <NSObject>
- (void)addItemViewControllerSS:(SetScoringTableViewController *)SScontroller didFinishEnteringItemSS:(NSString *)SSname;
#end
#interface SetScoringTableViewController : UITableViewController
#property (nonatomic, strong) id <SetScoringTableViewControllerDelegate> SSdelegate;
#end
GameDetailsTableViewController.h
#import <UIKit/UIKit.h>
#import "LocationViewController.h"
#import "SetScoringTableViewController.h"
#interface MainViewController : UITableViewController <LocationViewControllerDelegate, SetScoringTableViewControllerDelegate>
When I run this I get an error: "Cannot find protocol declaration for 'SetScoringTableViewControllerDelegate' even though I have.
The only way I have found to fix this problem is to put the "SetScoringTableViewController delegate in the LocationView Controller, but I know that is not right. Any help would be greatly appreciated.
You have a dependency loop:
SetScoringTableViewController.h
#import "GameDetailsTableViewController.h"
GameDetailsTableViewController.h
#import "SetScoringTableViewController.h"
But it looks like you can remove the #import "GameDetailsTableViewController.h" as there is no mention of it in the header file.
What you're experiencing is an an #import cycle. To break the import loop
remove this import line:
#import "GameDetailsTableViewController.h"
from SetScoringTableViewController.h and put it in a .m file.
Try to separate the delegate on a different .h file.

Trying to call custom delegate method of subclass of UITextField in iOS

I have a custom delegate that I have created for a subclass of UITextField. In the delegate class, I've declared an enum like this:
MyCustomDelegate.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import "MyCustomTextField.h"
#interface MyCustomDelegate : NSObject <MyDelegate, UITextFieldDelegate>
#property (nonatomic, strong)MyCustomTextField *customTextField;
#end
MyCustomTextField.h:
#import <UIKit/UIKit.h>
typedef enum {
EnumTypeA,
EnumTypeB,
EnumTypeC,
EnumTypeD,
EnumTypeE
} MyEnumType;
#class MyCustomDelegate;
#protocol MyDelegate <NSObject>
#required
- (void)methodA;
- (void)methodB;
#end
#interface MyCustomTextField : UITextField
#property (nonatomic, weak)id <MyDelegate>myDelegate;
#property (nonatomic) MyEnumType enumType;
#end
Now, I am trying to use this enum in conjunction with my custom UITextField elsewhere in my project, like this:
MyViewController.h
#import "MyCustomTextField.h"
#import "MyCustomDelegate.h"
#import <UIKit/UIKit.h>
#interface MyViewController : UIViewController
#property (weak, nonatomic) IBOutlet MyCustomTextField *mySampleTextField;
#end
MyViewController.m:
- (void)viewDidLoad {
[super viewDidLoad];
[self.mySampleTextField setMyEnumType:EnumTypeA];
}
However, I am getting the error, "No visible #interface for 'MyCustomTextField' declares the selector 'setMyEnumType'".
Can anyone see what it is I'm doing wrong?
Objective-C will automatically generate setter for you based on the name of the property (enumType) instead of the name of type (MyEnumType). So your setters should be the following instead:
[self.mySampleTextField setEnumType:EnumTypeA];

How to overcome a #import loop?

Imagine I have two header files: SomeFileA.h and SomeFileB.h
SomeFileA.h includes SomeFileB.h, and SomeFileB.h includes SomeFileA.h.
This creates a loop and confuse the compiler. How can we overcome this?
You should "forward declare" your classes. This tells the compiler that the class exists, but without the need to actually import it.
SomeFileA.h
#class SomeFileB // <-- This "forward declares SomeFileB"
#interface SomeFileA
#property (nonatomic, strong) SomeFileB *someFileB;
...
#end
SomeFileA.m
#import "SomeFileB.h"
#implementation SomeFileA
...
#end
And the same thing, but the other way around in SomeFileB
SomeFileB.h
#class SomeFileA // <-- This "forward declares SomeFileA"
#interface SomeFileB
#property (nonatomic, strong) SomeFileA *someFileA;
...
#end
SomeFileB.m
#import "SomeFileA.h"
#implementation SomeFileB
...
#end
If you don't use a class in the header, you don't need to forward declare it.
#interface SomeFileA
//I took out the property for SomeFileB.. no need for the #class anymore.
...
#end

Declaring delegate protocol in the same file

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.

Resources