I have an iPad application which consists of a splitviewcontroller - From the detailview of the splitview i open a modalviewcontroller(NearbyViewController) which has a button that shows a popover(RadiusViewController) with a picker. This works just fine, but when i select a value in the picker i want to call a method on the modalview controller, but i can't figure out how to do this?
My "NearbyViewController" imports the "RadiusViewController.h" because i access certain data in the "RadiusViewController", but i also need to be able to send data from the RadiusViewController back to NearbyViewController, but if i import the NearbyViewController.h file in the RadiusView then i get compilation errors due to them trying to import eachother.
This is a common problem and it's very easy to solve. The solution is simply to make the imports in the .m files instead. If you need the type to be known in the .h file, you simply use forward declaration.
#class ClassName;
It's as simple as that.
EDIT: A more thorough explanation:
Generally in the .h file the methods and properties of the class doesn't need to be known. All you need to do is tell the compiler that there is a class named ClassName. The compiler doesn't need to know anything else about the class at that point. In the .m file you will need to know the methods and properties of that class or you will not be able to use it. So in the .m file you import the class.
Just to be clear:
// SomeClass.h
#class ClassName;
// SomeClass.m
#import "ClassName.h"
This is called forward declaration. You can google it to learn more or read an introductory book on programming. It's a very basic programming concept and it's important that you learn it.
Related
I am working with a objective-C framework.
I have a public framework header "MyPublicHeader.h" exposed to the client application. I have a custom class in the project,
//MyCustomClass.h file
#interface MyCustomClass.h
- (NSString *) methodA;
#end
//MyCustomClass.m file
#inplementation
- (NSString *) methodA {
}
#end
If I want the client to instantiate the class I have to make it as public framework header. I want to hide the interface as a curiosity, is there any way to do it???
First know that nothing can be truely hidden in Objective-C due to the nature of dynamic dispatch and the features in the runtime which allow discovery of methods etc.
That said there are a number of ways to do this, a couple:
Use a subclass. Declare a superclass and publish its interface as part of your framework. Make your class a subclass of this and publish its interface only within the framework. You define one or more init methods in the superclass which return and instance of the subclass, and if you want to expose any further API define it in the superclass with dummy (or faulting) implementations and less the subclass override etc. This approach is similar to the model used for classes like NSString.
A .h file is just text and you can exploit this: make two .h files, say MyCustomClass.h and InternalMyCustomClass.h. In the first just declare the interface with no members, or the API you wish to make public, and publish that to users of the framework. In the second declare the real interface used within the framework. You must make sure to keep all three of the files (2 .h, .m) in sync. This approach would be call little naughty by some, "here be dragons" by others, or "needs must" by yet others...
You might also like to look into "class extensions" which are related to categories.
Hope that satiates your curiosity a little, and keep up with the curiosity its good (except for cats)!
You could create an empty wrapper class which only holds a reference to your MyCustomClass object.
When they create this object you secretly instantiate an object of your MyCustomClass inside and extract it when they pass you an object of the wrapper class.
Not sure if this is exactly what you want to achieve, but could be a workaround.
I am building an app, where I have made a Menu class which is a tableview being presented to the user (containing link to different view controllers, which should be presented on click).
Instead of importing any viewc. header in either of my viewc.'s I decided to import all the view controllers headers into my Menu.h. This way I can make all app navigation from menu class. I will then import menu.h in my appDelegate.h and then import only appDelegate.h to all my view controllers. Are there any unforeseen downsides to this, or should I do it another way? Thanks
If it compiles then that's OK, however it's considered best to use forward declarations in header files where ever possible to improve compile time.
Any custom type can be forward declared in the header file, of the using class, with:
#class YourViewController;
and then within the implementation file of the using class, include the actual header file:
#import "YourViewController.h"
Using forward declaration can also stop dependency loops where A.h includes B.h, which itself includes A.h.
Doing this you will have a include loop (which is bad !).
Menu.h is importing ViewController1.h
AppDelegate.h is importing Menu.h (and ViewController1.h)
ViewController1.h is importing AppDelegate.h (and Menu.h (and ViewController1.h))
A clean solution is to use Forward declaration when needed, and doing your import in .m files
For example, there're three classes, Aclass, Bclass, and Cclass.
Aclass initializes some instances of Bclass and Cclass as different children. Normally I'll import Bclass.h and Cclass.h in Aclass.h or Alcass.m. So far Bclass and Cclass don't know each other yet. However there're cases for example Bclass needs to know Cclass's properties and methods. One way to do this is to import Cclass.h in Bclass.h or Bclass.m; later on Cclass needs to know about Bclass, then I'll import Bclass.h in Cclass.h or Cclass.m. Sometimes if there's "import cycle" that can't pass the compiling, then I may change one of the import from xx.h into #class Xclass.
Though this works, however I feel it's not the right or delegate way to do. I used to use delegate only to avoid importing parent's class. So what's the best way to design if one class needs to know about it's siblings?
if you are getting import cycles, what you should do is just import the headers into the .m files, then if you really need that object in the .h, use #class ClassName; at the top of your header to promise to the compiler that the type of object exists.
edit:
my bad, tl;dr'ed the last sentance, that is the correct way to approach it
If some one can brief on declaring instance variable inside .h file inside #interface braces and in .m file #interface braces. like this below
#interface ViewController : UIViewController { NSString *str ; }
#interface ViewController () { NSString *anotherStr ; }
Thx
There's even a third place where you can define instance variables: at the implementation statement:
#implementation ViewController { NSString *yetAnotherString; }
AFAIK, in the olden times you could only define the instance variables in the main interface. The other two places were added later. You can also mix them (as long as they have different names).
The advantage of defining the variables at #implementation and also the class extensions #interface ViewController () level (when done inside an .m file) is that you can hide implementation details from users of your API. In other words, if someone reads the .h file (s)he doesn't know about the variables. This makes the visible API cleaner and is also a concept called "information hiding" which is quite important in object oriented programming: don't expose too much implementation details so you can change the implementation without breaking code using the class.
Note that you can also define IBOutlet variables at all three levels and Interface Builder will detect and use them!
So when you're deciding where to define the variable you can simply ask yourself: Do other people need to see the variable when they see the .h file? IMHO this is only true when you need/want to make a variable #public. For all other cases, you can define them at the class extension or implementation level to make the API cleaner.
Whatever you declare in ViewControllerA.H is public. It means that other view controllers that contain the ViewControllerA object can access use the methods or variables directly. Whatever you declare in .M is private, other view controller can not access it immediately.
As for my own practice, most of the variable (I don't use much) or properties I declare in .M to prevent other view controller to access it directly. It is just like one concept in Object Oriented Programming - Data Encapsulation.
Note: Please be reminded that this should not be confused with #public, #protected, #private like DarkDust mentioned below. It will be another different topic.
In objective-C while you declare the member in .h file, it becomes visible to the other file when .h file is imported as header.
By default all member variables are private. So, user can not use them directly. But with methods of runtime.h and setValueForKey give them an alternate way to set those variable.
To avoid the user to do such mischief, its advisable to declare your private variables in .m file. They are called extensions as well.
For example you have created a variable in your appdelegate file. Now import appdelegate.h file to other .m file. Get the instance of appdelegate by sharedApplication delegate. Now you can set value by below way.
[appdelegate setValue:your_value forKey:#"name of variable"];
Though it was private, user could do so. Its because when you check for auto suggestion window, it will list down your private variable with strike through. To avoid getting those variable inside this window, it is advisable to declare them in .m file.
I have been stumped on this for awhile. I have asked multiple developers I know and they think I have forgotten to "#import the .h file". But I know I have, I have tested the class in more than one file in my project. It only works in the "VNDecalLevelListViewController.h" ( which I will post its implementation if a picture). When I try and call my "initForNewDecal" method for my "VNDecalCreatorViewController.h" class in my "VNAdminViewController.h" class I received the error that this method has not been declared in "VNDecalCreatorViewController.h". But when I call it in my "VNDecalLevelListViewController.h" class it works.
I am able to allocate and use "init" to create the object and it loads with a work around I made. But I am new to programming and I can tell there is definitely a better solution.
As you will soon see as i got to allocate the VNDecalCreatorViewController in the " VNAdminViewController" the option to initialize VNDecalCreatorViewController with the proper initializer "initForNewDecal" isn't even a option.
Anyone know why this is happening ? I want to write the code right I am trying to figure out why my header file is only being read in one class.
I guess this is because you mutually imported between the two class Creator and Level. I mean you may have #include "VNDecalCreatorViewController.h" in VNDecalLevelListViewController.h and vice versa. The solution is to use #class to forward declare any classes you may need to reference instead of #import'ing the header.
Make sure that the method is declared in the header file and implemented in the .m file.