Event name when IBOutlet is assigned in the controller - iphone

I would like to run some logic in my Controller class once all IBOutlets get assigned. What method do I need to override in the Controller class to receive this event?
Thanks,
Rui

The -(void)awakeFromNib method is called after the outlets are connected. There's a good article on it at Cocoa is my Girlfriend

Related

Shake event detection in all view controllers

Is this possible in iOS, or do I really have to register a shake event detection in every single view controller?
I want that a user of my app can shake his iPhone to return to the root. Regardless of the current view controller.
I've done this by writing a category on UIViewController. This way you don't need to subclass anything, you can implement it even if the user interface has been finished already.
In my implementation, the VCs will respond to the shake unless the specific VC has opted out of the mechanism. Opting out is done by setting a BOOL ivar to NO in the specific implementation. The shake mechanism will look for this ivar using key-value-coding and ignore the shake if the ivar has been set.
I'd further refine this by allowing only the VC to respond which is currently visible.
edited post (old information was wrong)
in your case I would write my own ViewController which subclasses UIViewController, implements the motion-delegates of UIResponder and will then call the popToRootViewController on the navigationController-property of the ViewController. And everytimes you create a new ViewController you should subclass your ViewCOntroller and not UIViewController. So every ViewController is able to receive the shake-event but it is only written once in your code :)
This is just a guess, but maybe you could do it by subclassing UIApplication (not your app delegate, the actual application). UIApplication is a UIResponder, so you can make it the first responder, and provide a motionBegan or motionEnded method on it.

I can't get my head round - (void)playInputClick;

I have an inputAccessoryView for a UITextField set up, which is loaded from a XIB when needed (in the exact same way as Apple's KeyboardAccessory example).
I'm trying to get the buttons on it to click when pressed using the playInputClick function but I can't work out how. The Apple documentation says that I need to add add a delegate method to the view, but the view was created purely in interface builder so I don't see how I can do this.
Does anyone know how to make this work? There seems to be no example code of this method being used anywhere on the internet.
I've been having the same problem and finally figured it out.
If you implement the protocol in a UIViewController it does not work. It needs to be implemented in a UIView subclass.
So to get it working, I created a view in interface builder with a view controller. Then I added another class which is a subclass of UIView. This class implements the UIInputViewAudioFeedback protocol. Then in interface builder I went to the Identity inspector of my view and changed the class to my UIView subclass which implements the UIInputViewAudioFeedback protocol. And the keyboard click sound is now working.
My view controller is still calling the [[UIDevice currentDevice] playInputClick], all I did was move the code for the UIInputViewAudioFeedback protocol into a UIView Subclass and set my views class to my UIView sublass.
Assuming you are trying to do this in an inputAccessoryView:
In the .h file, indicate that you implement the UIInputViewAudioFeedback
#interface YourAcessoryView : UIView <UIInputViewAudioFeedback>
In the .m file, add this method to satisfy the protocol
- (BOOL)enableInputClicksWhenVisible {
return YES;
}
When a button is pressed, do something like:
- (void)buttonPressed:(UIButton*)sender
{
[[UIDevice currentDevice] playInputClick];
// do more stuff
}
You need to implement a view controller class, and in the interface builder assign the files'owner as this class. Connect the view controller's view to your view.
Once you have done that you can implement the delegate in the view controller.
Its pretty simple and straight forward. Basically your view will be a member of a view controller class.

How to access variables of a ViewController in a subclass?

I guess this is basic, but I can't get my head around this.
I used to have only one ViewController in which all my variables were defined, e.g. an UITextView named myTextView. I also had methods in this ViewController for handling events that relate to myTextView, such as - ()hideKeyboard { // do something with myTextView or - (void)keyboardWillShow:(NSNotification *)notification { // do something with myTextView.
As my program became bigger and bigger, I thought about using subclasses, especially for other views. So I started a subclass, eg. mySubClass.h and mySubClass.m, in which I had another UITextView (for argument's sake myOtherTextView). In order to incorporate mySubClass, I #imported it into my ViewController and added a #class mySubClass; and could then produce instances of this class so as to use it in my App.
So far so good. As you can imagine, all the nice methods I defined in my ViewController for what should happen when an UITextView is edited (such as hiding keyboard etc.) didn't work for the UITextView in mySubClass.
It was then suggested to me that I should make another class in which I had all the keyboard events and subclass my ViewController and mySubView to it:
#interface ViewController : MyKeyboardEventsViewController
Now, the problem I am seeing is that I won't be able to access all the views, textviews, textfields etc. that I have created in my ViewController (e.g. myTextView which I mentioned earlier).
How can I achieve that all the variables that I have defined in my ViewController will also be available for MyKeyboardEventsViewController? Or is there another way to handle this?
Basically, I don't get how MyKeyboardEventsViewController will be able to access variables in my ViewController which it will need (e.g. the UITextView in question, or the accessoryView which will pop up etc. etc.).
Any suggestions would be very much welcome.
Example:
Class A contains a ivar UITextField textField
Class B subclasses Class A and thus it already contains ivar textField
Note: it's not the other way around. Class A does not "see" what ever is created in Class B.
When ever you subclass a class you give your new class the same ivars end methods of that subclassed class.
I hope this is what you were asking for.
EDIT
So for your example I would do the follwing:
Create a class "MyUIKeybordEventResponder"
Implement all the responder methods like - (BOOL)textFieldShouldReturn:(UITextField *)textField
Subclass your ViewController from "MyUIKeybordEventResponder"
Note method textFieldSHouldReturn has a parameter UITextField so it knows which textfield was pressed. So in a way it receives your textField from the subclass.
If I'm understanding this correctly, you have a UIViewController with MyKeyboardEventsViewController as an instance variable and you want to communicate between the two? If that is the case, one option would be to create a protocol.
#protocol MyKeyboardDelegate
- (void)closeAccessoryView;
#end
(Note - make whatever methods in the protocol that you need, this is simply an example)
In your MyKeyboardEventsViewController you then include the protocol file, and create an ivar
id <MyKeyboardDelegate> delegate;
Also make it a property and synthesize it.
Whatever class that is going to create the keyboardviewcontroller should delcare themselves as conforming to the protocol.
#interface MyViewController : UIViewController <MyKeyboardDelegate>
...
#end
When you create the MyKeyboardEventsViewController, set the delegate.
MyKeyboardEventsViewController *eventsVC = [[MyKeyboardEventsViewController alloc] init];
[eventsVC setDelegate:self];
Now just implement the delegate method and perform whatever action that is necessary.

How do runtime-created sub views communicate with the view controller?

In my iPhone project I have a UIViewController in which I add an instance of a subclass of UIView. From this instance I need to communicate back an integer to my view controller. My current solution is to send a message from my instance to my App Delegate which sends a message to the view controller. It works, but it feels a bit messy.
Is there anyway I can send a message straight back to the view controller?
I would love to be able to do something like [super doSomething:123];
Any ideas?
Thanks
This is the kind of thing that NSNotificationCenter was provided for. Once you get handy with sending and receiving notifications, your message-passing gets a WHOLE lot simpler.
One of the classic things people confront is how to get a pointer to the object they want, in order to tell it about something. How do I, for instance, tell the ViewController two slots back up the UINavigationController stack that the user just changed this data field? So you dig into the stack, offset back by some magic number of elements in the stack, build public setters on the fields you want talk to... It's super cumbersome.
Compared to registering as a notification receiver in one place, and then firing a notification in some complete other place when the data changes. It's kind of magical, after doing all the "dig through the view hierarchy" work.
Um, I'm not sure I understand your problem correctly. You have a class derived from UIView which needs to send a message to another class derived from a UIViewController. It sounds like you are creating the UIView instance programmatically. Is there any reason my you could not have a property on the UIView which refers to the UIVIewController and just use that to send it a message directly.
You cannot use [super ...] because the super of your UIView derived class would be UIView.
Or am I miss-understanding the issue :-)
If I understand correctly, you want to send a message from your subclass of UIView to the view controller.
That means your subclass of UIView needs to have a property or ivar which is the view controller. The easiest way to do this is to add it as an outlet and connect it to the view controller in the nib file.
Generally you should not go via the app delegate. Having a typed pointer link is also less than ideal.
The optimal way of communicating - Apple does it like this as well - is to create a delegate protocol. When creating the view controller you pass a pointer to the delegate as id . Then when it gets to sending the message you ask the delegate:
if ([delegate respondsToSelector(didFinishSomething:)])
{
[delegate didFinishSomething:info_to_pass];
}
If you want to be extra-sophisticated then you can also add a pointer to the calling class instance. Like:
[delegate myViewController:self didFinishSomething:info_to_pass];
This way you always know what kind of class the message is coming from.
If there is more than one place that needs to be notified of a change, then instead of delegation you will use notifications.
In my iPhone project I have a
UIViewController in which I add an
instance of a subclass of UIView.
This implies that you have both a reference to the instance of the UIView subclass and the UIViewController in the same scope. I.e. something equivalent to:
UIViewControllerSubclass *myViewController;
UIViewSubclass *myView;
(It doesn't matter if they are actually instance variables or, even, globals)
And once those two variables are initialized, somewhere you do something like:
myViewController.view = myView;
In your UIViewSubclass, add a property that points back to your UIViewControllerSubclass:
#property(assign) UIViewControllerSubclass *myController;
Then, when you do the above assignment, add:
myView.myController = myViewController;
From there, messaging your controller from your view is easy:
[self.myController yoManHereIsAnInt: 42];
Note that I used assign instead of retain because the controller already retains the view. If the view were to also retain the controller, you would have a cycle that would eventually lead to a leak.
No super about it. super is entirely related to the inheritance hierarchy of your Objective-C classes. What you are asking has nothing to do with inheritance and everything to do with how the various instances of objects in your application are connected together.
Simply add an outlet to your UIView subclass, connect it to its view controller in Interface Builder, and call your method on that. Here’s how that might look:
MyUIView.h:
#interface MyUIView : UIView
{
UIViewController *viewController;
}
#property (assign) IBOutlet UIViewController *viewController;
#end
MyUIView.m:
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
[[self viewController] setTitle:#"Hello from MyUIView"];
}

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?