Communicating between classes set up in nib, in code? - iphone

A beginner's question:
If, in your nib, you have the File's Owner linked to the ViewController class, and you also have a NSObject-derived class, how do you communicate between the ViewController class and the NSObject class within code?
For instance, suppose ScientificCalculatorView.xib looks like this
File's Owner (class: ScientificCalculatorViewController)
FirstResponder
View
Calculator (an object that has been linked to the Calculator class)
Obviously, I'd want Calculator to be reusable, so it could be used with a NormalCalculatorViewController or something like that. So that UI and the calculator code are separate. Does Calculator even need to be in the nib?
It's a beginners question, but I'm just trying to get my head around it.

There are two ways (at least) to handle this:
Set up an outlet in your ScientificCalculatorViewController defined:
IBOutlet Calculator *calculator; or something like that. In IB connect that outlet to your Calculator object. You will then be able to reference it in your ScientificCalculatorViewController.
In the - (void) viewDidLoad {} method, programmatically allocate and initialise a Calculator and set it to a property in your ScientificCalculatorViewController. In this case, you can remove the object from your NIB.

Related

Change UITextField.text from an external class swift

I'm trying to simplify my life by dividing chunk of related code into different classes.
But I encounter a problem: changing the ViewController property (like UITextField.text, etc.) from those classes.
I have tried creating protocol, but that was really messy so I want to find a new way to do this.
So, is there a simple way to change ViewController property directly from external classes? I'm using Swift 3 btw.
Thank y'all for helping.
If the object from where you want to change your label is a child object owned or presented by the controller, than you need to use delegation to comunicate back with the controller. You declare a protocol in that object from where you want to change the controller's label, and declare a weak property of that protocol type called delegate. When the controller creates that object you will set that object's delegate property to the controller itself (If that object is ownee by the controller, declaring the property weak you will not create a retain cycle). In the controller you implement the method declared in the protocol and in the implementation you can change the label.
The other case when the controller is owned or presented by the object from where you wanna change the label, in yhis case you just need a public method to do that.

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

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.

IBOutlet is NIL when using Forward Declarations to call a class?

I have been having huge issues with this, so I drew a diagram...
alt text http://tomsfil.es/7bdead0a.png
I successfully get to the CLASS A - METHOD B but at that point, IBOutlet Z is Nil? :(
Any ideas?
note
Somebody told me it might be an Overrelease and to use NSZombieEnabled but that confused me
It's all a matter of when you call the class. Right after you create a view controller with initWithNibName, nothing is actually wired up yet - it's only after the view is created that IBOutlets are created and wired in.
One trick is that you can simply ask the view controller for .view, like so:
myViewController.view;
Then the view will be created and the IBOutlet will exist. A better method though, is to create properties on the view controller that you set, and then either in viewDidLoad, or in viewWillAppear you use those properties to set values for your outlets.

Subclass of UIViewController initialising itself from a .xib can't use UINavigationItem?

I've finally had to give up the relentless search for an answer to this question, as I just can't find anyone that's asked it before! So hope someone can provide some insight. I'll start by explaining what I can do, then compare that with what I can't figure out how to do.
Suppose I have a custom VC called RootViewController. It contains an outlet of type MyViewController. My RootViewController has an .xib which contains a generic VC object dragged out of IB's palette which is given the class type of MyViewController, I set the right bar button item to a UIBarButtonItem called 'Cancel'. The RootViewController unarchives it's .xib, hooks up the outlet to the MyViewController object, I push said object on to the navigation stack which displays as expected, I have a view and a button on the navigation bar that says 'Cancel'.
The problem I have with this approach is that I want MyViewController to be re-usable across any object that might want to create a MyViewController. This therefore means that the "File's Owner" could be any object. Previously it was RootViewController, but what if another object wanted to instantiate a MyViewController? The Files Owner will be different every time. I also want it to be able to completely initialise itself from a nicely self-contained .xib. Basically, I want to do this:
MyViewController *myVC = [[MyViewController alloc] init];
And in the implementation of MyViewController, I write this:
- (id)init
{
if ( self = [super initWithNibName:#"MyViewController" bundle:nil] )
{
// Initialisation
}
}
This neatly hides the name of the .xib used to intialise the VC, uses all the goodness IB gives me in configuring the controller and view, and with MyViewController always being the owner, it means I solve the File's Owner problem too - it will work for any type of class that creates it.
So, in order to achieve this, I create a .xib, set the File's Owner to be of type MyViewController, drop in a UINavigationItem and add the UIBarButtonItem. I now have a .xib structurally the same as before, except it does not use IB's generic VC object as separate top level object, the .xib is the VC definition, rather than something that contains a VC definition.
So, given that File's Owner is a MyViewController and as such a subclass of UIViewController (supposedly inheriting everything you get by using a UIViewController from IB's palette), then I should inherit all the functionality of it's superclass... Except it doesn't.
When the .xib in unarchived, it does not hook up the UINavigationItem. Therefore, when it's pushed on to the navigation stack, none of the bar button items are displayed.
UIViewControllers navigationItem property is read-only, creating an outlet for it in iPhone OS 3.0 is therefore deprecated.
So, at the end of all this, how on earth does the nib loading code manage to connect IB's version of the VC object to the navigation item? And why, even though my object is a UIViewController through inheritance, will it not do it for my object? I am completely at a loss to fathom this out...
Thanks for reading this far! Hope to hear from you guru's
Only a UINavigationController sets UIViewController's navigationItem property. Do something like this:
MyViewController *viewController = [[MyViewController alloc] init];
[self.navigationController pushViewController:viewController animated:YES];
[viewController release];
Assuming you are in a view controller that already has a navigation controller. After you have pushed it, you will be able to access navigationItem from inside MyViewController.
Right, I think I get it now. I thought I'd post an answer to my own question as I've seen at least one other person ask a similar question, and both seem to point to the same conclusion, so I hope this will be of help to others.
Essentially (and this will sound obvious) a UIViewController is not a Proxy Object! It's not instantly obvious as we're all used to the idea that if any two objects inherit from the same base class, then their implementations are the same and they will behave in exactly the same way (assuming no customisation in the inheriting class). But an IB object's type is distinct from the class attribute you can assign to these objects.
They are not both UIViewController objects because their class attribute it set in such a way.
Simply setting the class attribute of these objects in IB does not mean that these objects are now UIViewController objects. A View Controller object remains a View Controler object, and a Proxy Object remains a Proxy Object. As far as IB is concerned, they are both very different beasts, they just happen to have the same class attribute.
Just take a look in to the .xib and you'll find your IB View Controller objects have been archived like this:
<object class="IBUIViewController" id="...">
...
</object>
And the Proxy Object (that is set to a subclass of a UIViewController) is archived like this:
<object class="IBProxyObject" id="...">
...
</object>
As you can see they are both very different types, one is a IBUIViewController and the other is a IBProxyObject - and then it starts to makes sense - you can't impose VC controller attributes on an object of type IBProxyObject.
It is also interesting to note the class type is an IBUIViewController object and not just a UIViewController object. Whether this is just a naming convention or not I don't know, but it could also imply that IB's view controller objects wrap the instantiated VC object, or is a factory object for it. For example, you can set a "Resize View From NIB" attribute in IB's view controller object - but I can find no equivalent property or methods in the UIViewController reference docs.
So in conclusion, if you're trying to instantiate an object programatically instead of using outlets to an IB object, be prepared to implement some of the initialisation that the IB version would otherwise provide for you...

Arbitrary objects to handle actions?

My question may be a bit stupid, but why can't any object instantiated in IB handle, say, button click? I mean I'm able to add my own object to a xib, and link outlets to cotrols and control actions to object's method, but once I press the button everything just crashes (uknown selector).
Do you guys have a hint around that?
EDIT: The code, as requested:
#interface TextController {
IBOutlet UILabel * textLabel;
IBOutlet UITextField * textField;
}
-(IBAction)buttonClicked:(id)sender;
#end
#implementation TextController
-(IBAction)buttonClicked:(id)sender {
textLabel.text = #"Ololo";
}
#end
Connections in IB are ok, just believe me. It's really hard to get them wrong with all this drag'n'drop stuff :)
EDIT 2: TextController is not a file owner (in this case it works fine). However, I just want to understand why I can't wire up an action to some object (may be even not a subclass of UIViewController).
You can wire outlets and actions to any object in the nib-file. Drag an NSObject form the library palette onto your nib-file, in Interface Builder. Then go to the Identity tab of the information palette and set the Class of your object.
This way you can instantiate any object of any class from your nib. If the target you want to hook to is statically created from the nib-file. Make sure that the file's owner have at least one reference to your object, or else it will be deallocated as soon as it has been created. Targets are not retained by the sender.
If the object you want to hook up should not be statically created from your nib, then implement awakeFromNib in a class that is instantiated from the nib-file and hook up the targets in code.
Last option is if you do not have any sub-class of your own in the nib-file at all. Then implement initWithNibName:bundle: in your UIViewController subclass, and hook up your targets in code after calling the super implementation.
post code, this usually means you dont have your connections wired up correctly. Is file's owner TextController in IB?