I have a project that generates applications for two targets.
One of the targets has to include one additional delegate protocol that should not be present on the other one. So, I have created a macro on Xcode and declared the header like this:
#ifdef TARGET_1
#interface myViewController : UIViewController <UIScrollViewDelegate, UIPopoverControllerDelegate>
#endif
#ifdef TARGET_2
#interface myViewController : UIViewController <UIScrollViewDelegate>
#endif
{ .... bla bla.... }
The problem is that Xcode is hating this "double" declaration of #interface and is giving me all sort of errors. When I put just one of the declarations the errors vanish.
How to solve that? thanks for any help.
If you're getting a redecleration there you must have defined both symbols. Double check that your TARGET_1 and TARGET_2 defines aren't being defined together
I personally don't hesitate to write something like:
#interface myViewController : UIViewController <UIScrollViewDelegate
#ifdef TARGET_1
, UIPopoverControllerDelegate
#endif
>
It looks ugly, but I believe it better reflects the semantics.
You can even do one better:
#ifndef TARGET_1
#protocol UIPopoverControllerDelegate
#end
#endif
#interface myViewController : UIViewController <UIScrollViewDelegate, UIPopoverControllerDelegate>
All of this doesn't invalidate the previous answers of course!
Related
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 don't like warnings lying around and this one has been bothering me. Any ideas on what I am doing wrong? I have tons of properties using this same approach and none of them are giving me warnings. Why doesn't Xcode recognize this one?
While the app works as expected, Xcode gives me the following compile time warning:
'OnlinePeerBrowser' may not respond to '-setMyParent:'
My property declaration in OnlinePeerBrowser.h
#import "WelcomeViewController.h"
#interface OnlinePeerBrowser : UIViewController <UITableViewDelegate, UITableViewDataSource, NSNetServiceBrowserDelegate> {
WelcomeViewController *_myParent;
}
#property (nonatomic, assign) WelcomeViewController *myParent;
OnlinePeerBrowser.m has
#synthesize myParent=_myParent;
I am getting the warning on setMyParent in WelcomeViewController.m here...
#import "WelcomeViewController.h"
#import "OnlinePeerBrowser.h"
#implementation WelcomeViewController
- (void)peerPickerController:(GKPeerPickerController *)picker didSelectConnectionType:(GKPeerPickerConnectionType)type {
...
OnlinePeerBrowser *controller = [[OnlinePeerBrowser alloc]
initWithNibName:#"OnlinePeerBrowser" bundle:nil];
[controller setMyParent:self];
}
Also, what is weird is that I can not use the dot syntax here either.
controller.myParent = self;
gives me the following error:
/Users/vesselhead/Development/iPhone/DJBox/WelcomeViewController.m:254: error: request for member 'myParent' in something not a structure or union
I feel like I must be missing something very simple.
The code you've posted looks correct. That means that the compiler is pulling in another declaration of the OnlinePeerBrowser class from somewhere.
Check for circular imports.
Check if you have multiple copies of the OnlinePeerBrowser.h file.
Add the line #warning Testing to your OnlinePeerBrowser.h file. That warning should then appear in the log when you compile. If that warning doesn't appear then that file isn't being picked up by the compiler.
If it's a circular import then don't import "WelcomeViewController.h" in "OnlinePeerBrowser.h". Instead, use a forward declaration in OnlinePeerBrowser.h, e.g. #class WelcomeViewController , and import "WelcomeViewController.h" in OnlinePeerBrowser.m
Sometimes Circular Imports create an issue with the compiler.
Instead of using
#import "WelcomeViewController.h"
in OnlinePeerBrowser.h move that line to the OnlinePeerBrowser.m and add
#class WelcomeViewController
to the OnlinePeerBrowser.h
this will allow you to set the Class of myParent and _myParent to WelcomeViewController and not have the Circular Import.
Alternatively:
you may want to use a #protocol that the WeclomeViewController would have to adhere to. Then you would only have to import the Classes in one direction.
the implementation for a Protocol property would be as Follows
//#import "WelcomeViewController.h"
#protocol OnlinePeerBrowserParent <NSObject>
#required
- (NSString*) informationFromParent;
#end
#interface OnlinePeerBrowser : UIViewController <UITableViewDelegate, UITableViewDataSource, NSNetServiceBrowserDelegate> {
id<OnlinePeerBrowserParent> _myParent;
}
#property (nonatomic, assign) id<OnlinePeerBrowserParent> myParent;
notice the Protocol is on the OnlinePeerBrowser.h so you can import the OnlinePeerBrowser.h and get the Protocol by default.
finally you implement the Protocol in the WelcomeViewController as so
#implementation WelcomeViewController<OnlinePeerBrowserParent>
- (NSString*) informationFromParent
{
return #"My Parental Info";
}
...... etc
I wish to create object of one class into another
I have 2 classes
MyviewControler
Checkout
I want to import Checkout into MyviewController
#import "Checkout.h"
#interface MyViewController : UIViewController <UIImagePickerControllerDelegate>
{
Checkout *checkout;
}
#property (nonatomic) Checkout *checkout;
#end
It is giving me error "Unknown type name checkout"
In MyViewController.h, before #interface add:
#class Checkout;
In MyViewController.m, add:
#import "Checkout.h"
you probably have a dependency cycle. use a forward declaration, which tells the compiler there is a class with that name without needing to see its declaration:
#class Checkout; // << the forward declaration
#interface MyViewController : UIViewController <UIImagePickerControllerDelegate>
{
Checkout *checkout;
}
#property (nonatomic) Checkout *checkout;
#end
// MyViewController.m
...
#import "Checkout.h"
forward declarations are preferred in the majority of cases. the exception to this is when there is a physical dependency (e.g. the superclass' declaration should precede the subclass'). forward declarations are good because they significantly reduce the build times and the complexity of include graphs and dependency.
good luck
If the error really is as you say:
Unknown type name checkout
(note the small 'c') then the problem is that you're using checkout as a type name instead of Checkout somewhere in your code.
import the file in MyViewController.m file too.
//in .m file
#import "Checkout.h"
#class Checkout; //this was missing
Also, give the property like this.
#property(nonatomic, retain) Checkout* checkout
and synthesize it in .m file
I have the following imports in my EquivalenceClassGroup
#import "MainViewController.h"
but then in my property in EquivalanceClassGroup.h:
#property (nonatomic, assign) MainViewController *myController;
I get this error: "Expected specifier-list before MainViewController when compiling
If I change the import to: #class MainViewController and comment out the import of MainViewController.h that error goes away but then then XCode can't find the methods in my MainViewController from EquivalenceClassGroup.m so from here:
-(id)initWithLetterNumbers: (int)numOfLettersInWord enteredLetter: (NSString *) str controller:(UIViewController *)controller {
myController = (MainViewController *) controller;
letterArray = [myController getLetterArray];
[myController getLetterArray];
I get: "Method -getLetterArray not found return type defaults to id" on that last line
I have this method defined in the MainViewController: -(NSArray*)getLetterArray;
and there are no errors in that interface file or the m file. In the equivalence class if I type in [myController then space, I cant seem to find any methods.
From the MainViewController class I do import the EquivalenceClassGroup and use the methods without any problems
You have to make sure that you import the MainViewController.h file in your .m file. All the #class does is tell the interface that there is such a class, but it doesn't tell it anything about the class. That is what #import essentially does. The #class in the .h file is just good programming practice to make sure that you are doubling importing or anything. Hope that helps!
I think you have to write #import "MainViewController.h" in EquivalanceClassGroup.h file and
#class MainViewController in MainViewController.h file.
#class MainViewController
in your EquivalenceClassGroup.h
#import "MainViewController.h"
in EquivalenceClassGroup.m
This is called "forward declaration" and is quite common.
I'm trying to mix C++ and Objective-C, I've made it most of the way but would like to have a single interface class between the Objective-C and C++ code. Therefore I would like to have a persistent C++ object in the ViewController interface.
This fails by forbidding the declaration of 'myCppFile' with no type:
#import <UIKit/UIKit.h>
#import "GLView.h"
#import "myCppFile.h"
#interface GLViewController : UIViewController <GLViewDelegate>
{
myCppFile cppobject;
}
#end
However this works just fine in the .mm implementation file (It doesn't work because I want cppobject to persist between calls)
#import "myCppFile.h"
#implementation GLViewController
- (void)drawView:(UIView *)theView
{
myCppFile cppobject;
cppobject.draw();
}
You should use opaque pointers and only include C++ headers in the file that implements your Objective-C class. That way you don't force other files that include the header to use Objective-C++:
// header:
#import <UIKit/UIKit.h>
#import "GLView.h"
struct Opaque;
#interface GLViewController : UIViewController <GLViewDelegate>
{
struct Opaque* opaque;
}
// ...
#end
// source file:
#import "myCppFile.h"
struct Opaque {
myCppFile cppobject;
};
#implementation GLViewController
// ... create opaque member on initialization
- (void)foo
{
opaque->cppobject.doSomething();
}
#end
Make sure that all files that include GLViewController.h are Objective-C++ sources (*.mm).
When you include C++ code in the header of your view controller, all sources that import this header must be able to understand it, so they must be in Objective-C++
You need to declare the C++ objects in an interface block in your .mm file.
In .mm:
#include "SomeCPPclass.h"
#interface SomeDetailViewController () {
SomeCPPclass* _ipcamera;
}
#property (strong, nonatomic) UIPopoverController *masterPopoverController;
- (void)blabla;
#end
I think you need to set the following flag to true in your project settings:
GCC_OBJC_CALL_CXX_CDTORS = YES
This should allow you to instantiate C++ objects in your Objective-C classes.