I have a series of UIView subclasses that are added as subviews. Each subview can be dragged and dropped. When they are dropped (touchesEnded), I need to run a method in the viewController to do some work. I currently have the touchEvents handled in each subview class. Should I be handling these touch events in the viewController or should I be passing a pointer to the parent viewController as a property of each class I have added as subviews?
UPDATE: Or is this a job for NotificationCenter?
UIViewController is a subclass of UIResponder, and instances are automatically inserted in the responder chain behind the views they control. As a result, you can implement the same event methods in subclasses of UIViewController as in subclasses of UIView, and they will 'just work'; that is, they'll be called automatically.
So if your view controller needs to respond to -touchesEnded:withEvent:, just implement the method directly in your UIViewController subclass. If the view also needs to do something in response to the event, you can always send it a message from within your -touchesEnded:withEvent: (or whatever) implementation.
You might try delegating your desired touch handling event from your uiview subclass to the uiviewcontroller using a delegate protocol. The view controller can set itself as delegate as it instantiates or adds each subview.
In MVC paradigm, if you want to handle a touch that's specific to a V view's internals (button appearance/location), then you might want to handle that touch in the V view, but if the touch effects some state outside the view (it's position in a bigger window, etc.) you might want to pass handling that touch up to the C controller to set state in the M model.
Related
I have created a UIView class. In this class it has touchesbegan and touches moved functions etc. When I create an instance of this class in my UIView controller they don't work.
Is it not possible for the instance to access these functions? I know the class works because if I drag a UIView onto the View Controller and assign it with the class I can drag it and resize it etc.
I have created a UIView class. In this class it has touchesbegan and
touches moved functions etc. When I create an instance of this class
in my UIView controller they don't work.
Check the userInteractionEnabled property of the view. The default value for any UIView is YES, so your view should track touches, but you may have disabled the view in your storyboard or .xib file.
Is it not possible for the instance to access these functions?
It's possible, and the entire touch handling mechanism relies on it. If your view is enabled, and it's not covered up by some other view, and there aren't any gesture recognizers that are stealing its touch events, it should be receiving touch messages.
I believe that UIView objects can delegate control to views in iOS programming. However, I thought this was already handled by an IBAction associated with an IBOutlet corresponding to the UIView.
In that case, what does it mean to drag a blue line (while pressing Ctrl) from the delegate circle of the UIView in my xib to File Owner?
Isn't the UIView already delegating to my view controller via an IBAction? The code seems to work if I don't specify anything for my UIView's delegate.
"Isn't the UIView already delegating to my view controller via an IBAction? The code seems to work if I don't specify anything for my UIView's delegate".
It looks like you're confusing the idea of the Target-Action Mechanism with delegation. While you could in a way think of target-action as involving “delegation”, it would only be in the most general sense of the word in that it’s the target (generally a controller) that handles and implements the action (the message). However, a Cocoa programmer would probably refrain from explaining the target-action mechanism by using that particular word – delegation – as it would be too easy to confuse it with actual Delegation.
When you “wire up” buttons and controls in the nib file to call IBAction methods in your controller object, that’s just the target-action mechanism at work. As you saw, the code works even if you "don't specify anything for my UIView delegate”, since target-action doesn’t involve delegation (in the Cocoa-sense of the word).
Delegation is generally used as an easier alternative to using subclassing to implement the desired behavior. For example, instead of having to create your own custom subclass of UITableView in order to have it know what data you want it to display, you can simply use the plain UITableView class, set its delegate to a controller class, and have the controller class implement the required/desired designated delegate methods. Using subclassing to accomplish that could potentially get complicated, since when you subclass, you need to have a full understanding of the inheritance chain and how all of the superclasses work.
File's Owner is just a fancy way of disguising the name of the class that the XIB is taking it's references from. When you drag the delegate outlet to your class, it's the equivalent of this line:
[self.myControl setDelegate:self];
When you drag while pressing CNTRL from an IBOutlet or IBAction to a UILabel, UIButton or something else, you are binding events or outlets to your controller.
A delegate sort of a controller that must implement specific functions depending on which type of delegate it is. For example, the UIViewController, which implements the UIViewDelegate protocol, can implement
-(void)viewDidLoad
the YourApplicationDelegate, which implements UIApplicationDelegate must implement
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
So a delegate is just a set of functions which define the behavior of an object, the classes that implement them can change this behavior.
I have subclassed UIScrollView and added my own custom delegate (currently called delegate). I want to add functionality such as notifying a user when an image is tapped and perform loading like the table view.
However, If I define my own custom delegate, I can not set the parent delegate for responding to events such as scrollViewDidScroll (I want the subclass to receive these events). Should I rename the delegate in my subclass? Should I be using super.delegate in some form? Does a standard exist for doing this? Thanks!
Does your custom delegate just extend the methods of UIScrollViewDelegate? If it does, just override the methods -scrollViewDidScroll etc and forward the messages onto your own delegate.
Maybe I've misunderstood your question, so I apologize if I have.
I'm trying to understand how these two are connected. Every time you make a UIViewController does it also automatically come with its own UIView?
Also are these from Cocoa or Objective-C?
UIViewController is a Cocoa Touch class built for the purpose of managing UIViews. It expects to have a view hierarchy, but you don't "automatically" get a view (this is slightly inaccurate; see edit below). Usually you will obtain views by calling initWithNibName on your view controller.
There is some built-in magic in Interface Builder which knows that if File's Owner is a UIViewController (or subclass), there is a property called view. That's about it.
Once you have linked a view controller and a view, the view controller does a fair amount of work for you: it registers as a responder for view touch events, registers for device rotation notifications (and handles them automatically, if you wish), helps you take care of some of the details of animation, and handles low-memory conditions semi-automatically.
Edit: correction—if you don't call initWithNibName or set the view property manually, the view property getter will invoke loadView if view is nil. The default implementation of loadView will see if you've set nibBundle and nibName and attempt to load the view from there (which is why you don't have to call initWithNibName, most of the time), but if those properties aren't set, it will instantiate a UIView object with default values. So technically, yes, it does automatically come with its own UIView, but most of the time that's of little value.
UIViewController doesn't automatically come with a view. You have to make a view in the -loadView method. By default, this loads the view from the nib file you've specified. You can also override this method to make a custom view if you prefer not to use a nib.
Also, the view is not created right when the UIViewController is created. UIViewController uses a technique known as lazy-loading to defer the creation of a view until the view is actually accessed for the first time.
i may be making more out of this because of the late hour. i am confused. i have multiple views i call from a viewcontroller class. typically they are called with a uibutton object. say i have two views. main and child view. here is how i would call the child while the main view is visible.
[self presentModalViewController:childViewController animated:YES];
now because i want to use touch events to call the child view i believe i am forced to initiate the events from with the main view's class.
so how do i call the child view from within the main view class as i would when i am in the view controller class.
thanks for any help!!
If I understand you correctly, you're wondering if you need to handle touches in the main view itself, rather than in the main view controller. If that is correct, the answer is no, you don't have to.
The way events work in Cocoa is that they propagate up through a chain of objects called the responder chain. The last/lowest object in the chain is given a chance to respond to the events first. In this case, that object is your "main view". If the object can not respond to the event, the event goes to the next object in the chain, what's called the object's next responder. This progresses up the chain until an object responds to the event.
The reason you don't have to worry about this is that a UIView's next responder is its view controller. This means that if you don't handle the event in your view, it propagates up to the view's controller (and, if you don't handle it there either, it continues up the responder chain). So, if you implement the -touchesBegan:withEvent:, -touchesMoved:withEvent, and the other event-based methods in your view controller and not in your view, you'll be fine.
For further reading on event handling in Cocoa, see this section of the iPhone Application Programming Guide.