I am relatively new to Objective-C.
I have come to a code on the web that has something like this on rootViewController.m (this is a navigationController based app).
#interface RootViewController (CManagerDelegate) <CManagerDelegate>
#end
#interface RootViewController (PViewDelegate) <PViewDelegate>
#end
two questions:
what are these lines doing in the beginning of rootViewController.m
what are these lines doing in code? Please explain the stuff in parenthesis and between <> in this particular case.
thanks.
In one sentence: The code you posted makes the RootViewController class privately conform to some delegate protocols.
Delegate protocols are used to let a class declare the fact that it understands the messages from another class's objects. For example, a view controller can declare that it understands a gesture recognizer's delegate messages.
The fact that the class internally uses the gesture recognizer is often an implementation detail not relevant to other clients of the class. It is best not to publish this fact in the public interface but put it into the implementation (.m file).
Categories (and class extensions) let you do exactly this: Make a class conform to a protocol without changing the main #interface.
A nice and elegant solution!
Read up on Categories:
http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/objectivec/chapters/occategories.html
And Protocols:
http://developer.apple.com/library/mac/#documentation/cocoa/conceptual/objectivec/chapters/ocProtocols.html
In fact, read all of Apple's Objective-c documentation before going any further:
http://developer.apple.com/library/mac/#documentation/cocoa/conceptual/objectivec/Introduction/introObjectiveC.html
Good luck.
Related
I'm getting the following error
Property 'navigationController' not found on object of type
I've inherited this project and not sure what's going on.
In my m file in didSelectRowAtIndexPath I have
[self.navigationController pushViewController:nextController animated:YES];
It wasn't a problem before as I was accessing app delegate navigation controllers, which were outlets. However, I've had to move away from this approach as it's causing me problems. I've converted the rest of my project. But in this circumstance, where the project isn't using a normal table view, the navigation controller doesn't look to be available. I have this issue in 7 other views. Hoping I could have fixed this, and keep this cleaner code?
I'm really puzzled by this, I think this is occuring as SetsStyleSectionController isn't a view controller but is NSObject.
However, even with this set to UIViewController, the code runs, but doesn't push either.
Changing SetsSectionController from NSObject to UIViewController isn't available.
I'm not sure how to proceed?
I'm in the process of moving away from pushing from app delegate.
Edit: Screenshot 2 discussed below
I see a couple of issues here. You have a misunderstanding about protocols and classes, and you also have an application that interface with a protocol that while well-intentioned is actually making your life much harder than it needs to be.
The first issue you're dealing with is some troubles grokking the difference between protocols and classes, and between adopting a protocol and inheriting from a class. Which is totally fine, this stuff isn't easy. Basically, a protocol is just an interface to an object, and a class provides both an interface and an implementation. In other words, a protocol is just a list of methods that can be called, and a class is both a list of methods and the code to execute those methods. To get a more complete explanation, perhaps you'll be better off going straight to the source - Apple's "The Objective-C Programming Language" will probably help you, so please read about classes and protocols there. I think having done that you'll see why you're not having success giving your id<SetSectionController> instance a navigationController property without explicitly defining one. But do let me know if you have specific questions about this afterwards.
The problem that's harder to fix is this SetSectionController protocol. It has several issues and describing them all is outside the scope of this answer. Here's the thing - the implementation basically requires objects that implement this protocol to know which navigation controller is associated with the table view. This has been up to now provided deus ex machina by coupling them to the application's delegate, and you are right to remove this coupling. But now you have to find another way to get the right data populated into the view controller to push it on the navigation stack.
I think you should move the push logic into the view controller, and for now have the section controller provide an interface that gives the view controller the information it needs. So say the section controller has an implementation like this pseudocode:
- (void)...didSelectRow...
{
id detailsForIndexPath = self.dataForRows[indexPath.row];
DetailViewController *vc = [DetailViewController new];
vc.details = detailsForIndexPath;
[APPDELEGATE.navigationController push:vc];
}
Then I'd add a method to SetSectionController called something like -dataForRow: , the implementation of which would be like the first line of the method above. Then, in your view controller, implement ...didSelectRow... like this:
- (void)...didSelectRow...
{
id<SetSectionController> sc = self.sectionControllers[indexPath.section];
id details = [sc dataForRow:indexPath.row];
DetailViewController *vc = [DetailViewController new];
vc.details = details;
[self.navigationController push:vc];
}
If your section controller is doing anything else useful in ...didSelectRow... make sure to either move it to the view controller or forward ...didSelectRow... on to the section controller for now.
While I do appreciate trying to make complex table sections easier to manage through polymorphism, this protocol wasn't the right way to do it. It blindly copies methods out of UITableViewDelegate and UITableViewDataSource without consideration of whether those are the right questions to be asking something responsible for a single section of a single table. If you still want to use it, I think it will take some significant refactoring to get it into a shape that actually makes your life easier rather than harder. Depending on the complexity of the per-section logic deviation, I might just scrap it altogether. But that's a whole other question really. Hope this helps!
What do you mean it "isn't available"? Do you mean you don't want to/aren't allowed to subclass UIViewController, or are you getting a compiler error? From your comment on your question:
SetsSectionController.h:12:34: Cannot find protocol declaration for 'UIViewController'
you are changing the wrong thing to alter your subclass. As an example:
#import <Foundation/Foundation.h>
#protocol foo <NSObject>
- (void) bar;
#end
#interface lolcats : NSObject <foo>
#end
To change your superclass you change the class name after the colon. Ex.
#interface lolcats : NSObject <foo>
becomes
#interface lolcats : UIViewController <foo>
and you're off and running. However, if you accidentally change the protocol requirement for the protocol
#protocol foo <NSObject>
to
#protocol foo <UIViewController>
instead, or change the protocol you adhere to to <UIViewController>, you'll end up getting the EXACT error you got. You might be confused because the protocol says the object adhering to it must also adhere to the NSObject protocol, and NSObject is also a type of object. The object and protocol are separate things, and all objects inherit from NSObject, and thus inherit the protocol. Basically, it's saying "objects using this protocol must be objects."
Why did you expect this to work? The object is just a standard NSObject that states it adheres to a protocol containing a few methods. Why would it have a navigation controller property? It hasn't inherited it from anything. Regardless, based on your error, you probably just changed the wrong thing. Make sure you change the superclass class name after the colon.
If I want to reuse a protocol to notify the master view controller of when the detail view controller is dismissed such as this:
UIView notification when modal UIImagePickerController is dismissed?
where would i declare this protocol? Is it best practices to keep protocols in separate files? Thanks.
Typically I (copying Apple's methods) declare protocols on the header of the class that will be interacting with delegates of that protocol. (E.g. the UIActionSheet header file holds the protocol declaration for UIActionSheetDelegate.) It doesn't really matter technically where you declare protocols, as long as you don't have a circular reference of #import statements. This won't normally happen because the class that interacts with the protocol does so to avoid needing to #import all of the other classes that will now implement the protocol. (UIActionSheet sends messages to your classes when it is dismissed through the protocol, and therefore doesn't need to #import any of your classes.)
If you have a protocol and several unrelated classes will be interacting with delegates of that protocol, that would be a good indicator to put the protocol in its own file, because the protocol isn't really associated with one particular class.
I think you should declare a catagory of UIImagePickerController in separate files.Like ImagePickerCtrlCatagory.h and ImagePickerCtrlCatagory.m
In the ImagePickerCtrlCatagory.h ,do like this
#import <Foundation/Foundation.h>
#protocol ImagePickerCtrlDelegate;
#interface UIImagePickerController (DissappearDelegate){
id <ImagePickerCtrlDelegate> delegate;
}
#end
I have an XCode project I am working on that has multiple views controlled by a tabBar that is throwing multiple instances of the error:
"cannot find interface declaration for '~my sub view name~', superclass of '~my sub view name~'
These sub views were created after the original project as new files. Each has a line of code like this:
#interface meViewAndEdit : meViewAndEdit
I see no #import statements either. The project fails to build and I am not sure what i should be setting these to. Should I be referencing my App delegate as the superclass? what is missing here?
UPDATE: (updated)
I changed the interface statements for each of my header files for the views i created as follows
#interface friends : UIView
BUT, it seems that i have a new issue that i'll have to research:
"UIView" may not response to "initWithNibName.bundle"
This is now present in each of the .m files for the views I created.
still learning, thanks in advance for your input.
When declaring a class in Objective-C, you need to specify the class name, as well as the superclass. In your code #interface meViewAndEdit : meViewAndEdit, you are essentially declaring a class that is a subclass of itself. Since you are trying to create a subclass of UIView, the class declaration should look as follows: #interface meViewAndEdit : UIView.
Also, in a comment in another answer, you asked whether or not you need to #import the app delegate in every class. The answer to this is usually no, unless you specifically need to access something involving your specific app delegate class.
I will also make note that it is conventional to give classes a capitalized name. For example, it should be MeViewAndEdit, rather than meViewAndEdit. You only should keep the first letter lowercase if it is the name of a variable or function.
EDIT: The reason that you are encountering the errors in your update is that you are trying to subclass UIViewController, not UIView. On top of this, instead of subclassing either one, you are subclassing the app delegate. Change your line of code #interface subviewname : my_app_delegate to #interface subviewname : UIViewController. You are trying to create a subclass of UIViewController, not my_app_delegate.
On another conventional note, it is never good to put underscores in a class name. Always name classes in camel case like MyAppDelegate, not my_app_delegate.
You need to #include the .h header files in all classes in which you are using them.
Here is my dilemma. I would like to have a text box and a button. The user types in text and then presses the button. Once the button is pressed, a text message window (using MFMessageComposeViewController) comes up. I don't know how to set this up. The problem is that the TextBox will require a delegate (UITextFieldDelegate) and the MFMessageComposeViewController will require an MFMessageComposeViewControllerDelegate. How can I have a .h file that declares a view that is more than one delegate?
I'm new to iPhone programming so any help on how to have an interface view that handles more than one delegate (so that I can have multiple types of controls in my view) would be really helpful!
A delegate does not need to be a view. Indeed, in most cases it probably shouldn't be. Often you will make a controller object the delegate, although this depends a lot on what you're doing.
The delegate protocols you need (MFMessageComposeViewControllerDelegate and UITextFieldDelegate) are quite distinct, so a single object can readily implement the methods of both without any confusion. But even if you are the same delegate type for several objects, the methods will be passed a pointer to the calling object so you can decide what to do case-by-case if necessary.
If you just mean how do you declare your class as implementing both protocols, you would do this:
#interface MyDelegate : NSObject <MFMessageComposeViewControllerDelegate, UITextFieldDelegate>
{
...
}
...although this presupposes that the protocols are formally required, which I don't think is the case here. In which case such a protocol list is unnecessary.
Otherwise, I probably am not understanding your question...
EDIT: OK, it seems like what you're looking for is how to link up the delegates at runtime. This varies according to the particular class, but for MFMessageComposeViewController you do this:
MFMessageComposeViewController* composer = ...;
id<MFMessageComposeViewControllerDelegate>* delegate = ...;
composer.messageComposeDelegate = delegate;
Easy, no? In this case the protocol is required, so you'd have to include it in the interface as described previously.
In general, if an object uses a delegate for anything, it will have a property or a method to allow you to set it, which you'll find in the documentation. Eg, in this case: Properties for MFMessageComposeViewController.
Note that delegate properties are conventionally weak references, so the objects in question need to be retained somewhere in your application.
I'm new to Objective-C and development on Apple's platforms, but hopefully I can frame this question in an understandable way regardless :)
I want to parse an XML feed for my iPhone app, and I decided instead of shoving all of the delegation methods from an instance of NSXMLParser into my view controller, I'd wrap this up inside of a FeedParser class. After reading a few docs and example code, here's what I came up with:
#protocol FeedParserDelegate <NSObject>
- (void)parserDidLoadEpisodes:(NSArray *)episodes;
#end
#interface FeedParser : NSObject {
id <FeedParserDelegate> delegate;
}
#property (nonatomic, assign) id <FeedParserDelegate> delegate;
- (id)initWithURL:(NSURL *)url delegate:(id<FeedParserDelegate>)theDelegate;
#end
Simple. Delegates of my FeedParser object just have to implement parserDidLoadEpisodes.
However, as I started actually making my FeedParser class use NSXMLParser, I realized that I didn't have to specify that FeedParser implements a protocol for NSXMLParser -- I could just implement the delegate methods that I wanted to do something with. I think I've noticed this with other classes that follow the delegate pattern, too, but not all.
So why wouldn't I too just not bother with specifying a formal protocol for my FeedParser class? It would cut away some perhaps unnecessary code. I guess the question is: why would I want to create a formal protocol instead of just doing something like just checking to see if the method is implemented on the delegate with respondsToSelector? Is it only so that the compiler will issue nice warnings if a required delegate method isn't implemented?
A protocol declared with #protocol is called a "formal protocol". The other way to do it is to declare a category (a set of additional methods) on NSObject, like so:
#interface NSObject (FeedParserDelegate)
- (void)parserDidLoadEpisodes:(NSArray *)episodes;
#end
Then simply define that method for any object that you want to be a feed parser delegate, and leave it undefined otherwise. This is called an "informal protocol".
Why are there two ways? Well, here's a hint: the informal protocols came first. What it comes down to is that they added formal protocols because informal ones weren't cutting it. Informal protocols make it too easy to forget an important method or try to use an object as a delegate for something it's not designed to work with.
Basically, for the cost of adding <FeedParserDelegate> here and there, you can get the compiler to do your debugging for you. The compiler will generate warnings for the most common delegate bugs, which saves you time if you make one of those mistakes. Why not take advantage of its helpfulness?
Always, always, always favor compile-time error checking over run-time. You could of course ask the class if it supports the method, but why ask when you can know?
The answer is no, you don't have to. But you should want to. :)
Adding a protocol makes the compiler check things for you. If you don't get those nice errors at compile time, then you'll get them later at run time when they're harder to track down.