iPhone Programming - How do I programmatically make a view that requires two delegates? - iphone

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.

Related

Obj-C, Property 'navigationController' not found on object of type, from NSObject class?

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.

What exactly does delegate do in xcode ios project?

I have just been learning iPhone apps development but I have a hard time in understanding what delegate actually means? Can anyone tell me with example what it does and how important it is? Thanks for any helps!
It's a key concept to understand conceptually so getting your head around how to think about it ahead of the technical details is important. Simply put, a delegate is a callback.
Two main scenarios to use delegates:
A class or control wants to abstract out the details on how to do work (like retrieve data).
Allow others to hook code into a pipeline.
Examples:
UITableView - a table view is just a control that knows how to render a list of cells. It handles all the heavy lifting of rendering, scrolling, etc... But, it has no idea how to load your data. So you implement a datasource delegate which has methods to get the cell data for a given row etc... That makes it easy on you. You just use the control and plug in the specifics for your data. The UITableView will do everything for you ... just answer a few specific questions for. A delegate answers those few specific questions.
A text control - you add a text control to your view and voila! you can type in it and alls good. But what if you want to do something when they start typing or when they're done typing? Well, the text control offers a delegate with methods that allow you to hook into the execution pipeline of the text control. It allows the text control to do everything for you and allows you to interject code where you need it. Many times, there's way to interject code to make a decision on whether something is allowed. The control will call back and ask, should I be able to do x? You can interject code and influence the behavior.
If you're creating a control or class, you can create your own protocol, datasource delegates etc... so your control can focus on doing what's advertised. For example, let's say you wanted to create a task control. You could:
First, create a contract. Hey, if you're going to provide data for my control, these are the questions I'm going to ask you. I'll take it from there... In this case, I'm going to ask you the number of tasks and I'm going to have you give me a task given the row number.
#protocol XXTaskBoardDelegate <NSObject>
-(NSInteger*)getTaskCount;
-(XXTask*)getTaskForRow:(NSInteger*)rowNumber;
#end
In the control or class, give the consumer a way to give us the delegate datasource class that will answer the questions the control will ask. At this point, the control is a pure control. It knows nothing about how you get your data. It's asking for an object (id) that implements a contract/protocol. id
#implementation XXTaskBoard
- (void)setDelegate:(id<XXTaskBoardDelegate>)newDelegate
{
// the control stores the delegate so it can callback and ask you questions.
}
Then, for the delegate class, in the header declare you implement that formal protocol
and in the implementation m file you provide the code.
#interface AppController : NSObject<XXTaskBoardDelegate>
{
//...
}
then, implement it in the implementation
#implementation AppController
- (NSInteger*)getTaskCount
{
return [model queryTaskCount];
}
- (XXTask*)getTaskForRow:(NSInteger*)rowNumber
{
return [[model tasks] getItem:(NSInteger*)rowNumber];
}
A delegate is an object that another class can pass messages to. In practice delegate classes have to conform to a delegate protocol.
For instance we will take a subclass of a table view controller. This is a delegate for your table view. First you define that it is a table view delegate by doing this:
MyTableViewController : UITableViewController <UITableViewDelegate>
This says that class MyTableViewController is a subclass of UITableViewController and CONFORMS to the UITableViewDelegate protocol.
Setting [tableView setDelegate:self] (or defining it as such in IB) then passes the self object to the tableview in order for the tableview to send messages to it.
The main message it sends is the didSelectRowAtIndexPath message which tells your class that the user has pressed a table view cell.
So the object that takes the click event (the table view) passes on the message that the cell has been clicked to the delegate object (which in this case is your MyTableViewController object).
Delegate protocols exist so that you can make sure that the delegate object has the necessary methods to deal with your messages. Methods in a delegate protocol can be #optional or enforced. Any methods that are optional don't have to be defined. In your MyTableViewController class the method didSelectRowAtIndexPath is optional - you don't have to have it. If the table view doesn't find the method it just won't call it.
However the cellForRowAtIndexPath is necessary and without it your app won't compile.
I hope this helps and is straightforwards for you. If you need any more info let me know.
Delegates are just way of getting callbacks from something. You pass a delegate (a pointer to an object that conforms to a protocol) to something and when it has new data for you or when an event occurs that something make a method call on the delegate.
For example, when events occur, like your app is put into the background or the app is about to terminate the UIApplication object will call your application delegate to let it know. When a CLLocationManager has a new GPS position is will call your delegate to pass it the new position. UITableViews call their delegates to get UITableViewCells to display in the table. There are many uses of delegates in iOS.

How do I have a class communicate to it's view controller that something has happened

I have a viewController that's running my game view. The viewController spawns instances of a Dots, which are subclassed from UIView that are added as subviews to the viewController view. Within the dots class I have certain behavior if they are touched (touchesBegan) but I'd also like touching the dots to add to the score which is a property of the viewController, but I can't see any way to communicate that out without ridiculous workarounds. What am I missing here?
Two options (but not the only ones) are NSNotificationCenter and delegate+protocol.
NSNotificationCenter is simpler to implement and use but not ideal in all cases. The viewController would call addObserver to indicate it is interested in some message. The dots would call postNotificationName to send the message to interested objects. Be sure to call removeObserver in the viewController's dealloc.
Delegate+protocol lets you define a more rigid, well-defined, compiler or runtime verifiable interface between objects. For details, see Protocols in the Objective-C Programming Language.
In your case, I think defining a protocol is the better option. The viewController would make itself the delegate of the dot objects. The dot objects would have a delegate property and call the protocol methods through the delegate property.
Why is the score a property of the ViewController in the first place? I can see having a property for the label that displays the score, but the score itself belongs in some kind of model object.
The advantage of this approach is that you could then use Key-Value Observing (KVO), adding your ViewController as an observer of the model object. In fact, this is pretty much what KVO was designed for: an easy way to notify an arbitrary number of observers about a change to a property.
Reference:
Key-Value Coding Protocol Reference
Key-Value Observing Protocol Reference
Model Object Implementation Guide

Can someone please explain delegates in objective-c?

I have been using Objective-C for a while and pretty much understand most of its features. However, the concept of delegates eludes me. Can someone please give a succinct and easy to comprehend explanation of what delegates are, how they are used in the iPhone SDK, and how I can best make use of them in my own code?
Thank you!
There are a couple main reasons to use delegates in Objective-C, which are subtly different:
Enhancing the base functionality of a framework class. For example, a UITableView is pretty boring on its own, so you can give it a delegate to handle the interesting bits (creating table cells, adding text to section headers, what have you). This way, UITableView never changes, but different table views can look and act very differently.
Communicating to parent objects in your dependency hierarchy. For example, you may have a view with a button that the user may push to do something that affects other views. The view will have to send a message to its parent view, or perhaps the view controller, so that it can create or destroy or modify other views. To do this you'd pass the parent object into your view, most likely through a protocol, as a weak reference (in Objective-C, an assign property). The view could then send any message declared in the protocol to the parent, or delegate, object.
This approach need not involve views. For example NSURLConnection passes event back to its delegate, which may be the object that created it, using this mechanism.
Essentially, all a delegate is, is an object that accepts feedback from another object. Put simply, when stuff happens to an object, it tells its delegate (assuming it has one).
For instance, lets say I have a UIViewController with a UITextView placed in the middle of the view. I set up my UIViewController to be the delegate of the UITextView. Then, when certain actions are performed on the text view (begin editing, text changes, end editing, etc), it tells it's delegate so it can do whatever logic it needs to do, like spell checking every time characters change, or dismissing the keyboard when it receives a return key press.
Delegate methods perform a similar function to callback functions in C.
Hope that makes sense :)
Best and simple concept I got from a Lynda.com Tutorial was: When you set a Delegate it means you have been given work to do. So, if you want to use methods that are written in a protocol method, you must implement them by searching in the Delegate Class Reference and using them. I hope it helped.
By the way, Delegates are excellents. They are your friends. They have been made to make your life as a programmer much easier.

What are AppDelegates in Objective-C?

I'm working through an iPhone tutorial (link text and it has me put in some code (a few times throughout the various tutorials) but it doesn't explain it at all.
In this code:
todoAppDelegate *appDelegate = (todoAppDelegate *)[[UIApplication sharedApplication] delegate];
What exactly is an appDelegate? What does the "delegate" at the end of the instantiation mean? Actually, what does the whole thing mean? (UIIapplication sharedApplication)?
I am a .Net programmer if that helps someone explain it better. I hate learning through tutorials because I always need to know what EVERYTHING does and no one explains everything.
Let's back up a little bit.
The square brackets ([ ]) are Objective-C's method calling syntax. So if Cocoa had a C# syntax, the equivalent syntax would be:
TodoAppDelegate appDelegate = UIApplication.sharedApplication.delegate;
In C#, you would use a static class for a class that only has a single instance. In Cocoa, the Singleton pattern is used to accomplish this. A class method (in this case, sharedApplication) is used to retrieve the single instance of that class.
Delegates in Cocoa are not like the delegate keyword in C#, so don't be confused by that. In C#, you use the delegate keyword to reference a method. The delegate pattern in Cocoa is provided as an alternative to subclassing.
Many objects allow you to specify another object as a delegate. Delegates implement methods that those objects will call to notify them of certain events. In this case, UIApplication is the class that represents the current running application (similar to System.Windows.Forms.Application, for example). It sends messages to its delegate when things that affect the application happen (e.g. when the application launches, quits, gains or loses focus, and so on.)
Another Objective-C concept is the protocol. It is similar in principle to a .NET interface, except that methods can be marked as #optional, meaning they classes are not required to implement the methods marked that way. Delegates in the iPhone SDK are simply objects that conform to a specific protocol. In the case of UIApplication, the protocol delegates must conform to is UIApplicationDelegate.
Because it's not required to implement every method, this gives the delegate flexibility to decide which methods are worth implementing. If you wanted to, for example, perform some actions when the application finishes launching, you can implement a class that conforms to the UIApplicationDelegate protocol, set it as the UIApplication instance's delegate, and then implement applicationDidFinishLaunching:.
UIApplication will determine if its delegate implements this method when the application finishes launching and, if it does, call that method. This gives you a chance to respond to this event without having to subclass UIApplication.
In iPhone applications, developers also frequently use the app delegate as a kind of top-level object. Since you don't usually subclass UIApplication, most developers keep their global application data in the app delegate.
A delegate is just an object that implements certain methods (basically callbacks). The NSApplication docs explain what its delegate is supposed to do and what messages it needs to respond to to.
And this isn't instantiation. The snippet you posted above doesn't create anything. It accesses whatever object is set as the application's delegate. [UIApplication sharedApplication] gets the object representing the application, and sending delegate to the application gets its delegate (if any).
to add more to the mix of responses and another point of view, delegates are objects that can (but don't necessarily need to) do work for another object.
So let's say you have objectA, and can assign to it a delegate (let's call it delegateObject).
From objectA's point of view, there are certain bits of work that may need to be done. Depending on the context, the actual work and the results of such work can be different.
So instead of having objectA implementing a method for all these instances, we'll say... let's have another object, delegateObject, do the work... and as long as the results are returned in the proper format, we don't care what delegateObject did to get there.
objectA will first check that delegateObject exists and that delegateObject has implemented a method to do the work asked of it.
To accomplish this, NSObject (which every Cocoa object inherits from) has this method:
- (BOOL)respondsToSelector:(SEL)aSelector
and objectA would do a simple test before sending a message to delegateObject, for example:
if ([delegate respondsToSelector: #selector(someMethod:sender:)])
{
[delegate someMethod:#"stuff" sender:self];
}
and because objectA only sends a message to its delegate if one's been assigned, delegate is not retained by objectA.
if we were to use UITableView as an example, it has a lot of UITableViewDelegate methods. One of them is:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
every time the user touches a row in a table, the UITableView object will first check that there's a delegate, if there's a delegate, it'll then check that the delegate has implemented the above method. If it does, then it'll send the message to the delegate. This method expects no return value, and UITableView will go about its merry way, regardless of what the delegate does. And if there is no delegate that implements that method, then nothing happens.