Why a Set of UITouch? - cocoa-touch

I was just curious to why the UIResponder method returns a Set of UITouch objects as opposed to just an Array
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?)
I can't quite wrap my head around what the benefits are or what the purpose behind it. Hoping someone could explain what is happening in the background and how do I eventually end up with a Set of UITouch. For example if I were to drag two fingers across the screen wouldn't that be an Array of UITouch objects?

Most of us can only speculate about why UIKit reports a set rather than an array.
Here's my guess: it emphasizes that the touches aren't in any particular order and might not be in the same order from one event to the next. Since there's no subscript operator for Set or NSSet, it's harder to make the mistake of storing the index (0, 1, 2, etc.) of a touch for use when processing a later event.
It may also be an implementation detail. UIKit only reports touch events to your app at 60 Hz (on most devices), synchronized with the screen refresh. If the hardware supports reporting touch events more often than 60 Hz, UIKit needs to coalesce multiple events for the same touch. This coalescing occurs automatically, in a sense, if UIKit stores the updated touches as a set instead of as an array.

"Sets" and "Arrays" are both collection objects, so yes, all touches could be returned in either, or a dictionary for that matter. The reason, I imagine, that Apple chose to return a set is twofold:
Touches are unique. Objects in an array can appear multiple times, in a set they cannot. Since each touch is only one touch, they make more sense in a set.
Touches are unordered. Objects in an array are ordered, in a set they are not. How would you fix the order of touches? Which occurred earlier perhaps? Or which are leftmost, or most firm, etc... there is no natural correct order so they are unordered, hence best fit to a set.

Related

NSCell vs NSView: when many controls are needed

I am aware that Apple is deprecating the use of NSCell in favour of NSView (see AppKit 10.10 release notes). It was previously recommended that NSCell be used for performance reasons when many controls were needed.
I have spent considerable time implementing a custom control that required many subViews and the performance using NSView-type subViews was not good. See related stackoverflow discussion What are the practical limits in terms of number of NSView-type instances you can have in a window? I was struggling with 1000-2000 in-memory objects (which doesn't seem a lot). What is the actual reason for this limitation?
One thing that confuses me on the above is View-based Cocoa NSTableViews. You can create tableViews with more than 1000-2000 cells and they don't seem to have poor loading and scrolling performance? If each of the cells is an NSView then how is this achieved?
If there are practical limits, then what are Apple thinking when they say they are deprecating usage of NSCell's? I am sure they are aware that some controls need a large number of subViews.
Further, an (probably outdated) Apple Developer Guide give the following explanation for the difference between NSView & NSCell which I need explained further:
"Because cells are lighter-weight than controls, in terms of inherited data and behavior, it is more efficient to use a multi-cell control rather than multiple controls."
Inherited data: this would surely only cause "bloat" if the data was being used => and it would only be used it you needed it?
Inherited behavior: methods that you don't use in a class/object surely can't cause any overhead ?
What is the real difference between the lightweight NSCell versus the heavyweight NSView other than that it just seems to be conventionally accepted?
(I would really like to know.)
A brief and incomplete answer:
NSCells are about drawing state, and not much else. NSViews must draw, but also must maintain and update all kinds of other information, such as their layout, responding to user input events, etc.
Consider the amount of calculation that must happen if you resize a view that contains many hundreds of subviews: every single subview position and size must be maintained according to the existing constraints for the view layout. That alone is quickly a very large amount of processing.
NSCells, in contrast, don't exist in a layout in that way. Their only job is to draw information in a given rectangle whenever asked to do so.
One thing that confuses me on the above is View-based Cocoa NSTableViews. You can create tableViews with more than 1000-2000 cells and they don't seem to have poor loading and scrolling performance? If each of the cells is an NSView then how is this achieved?
NSTableViews re-use views. The only views actually generated are those that are visible, plus maybe a row of views above and a row below the visible area. When scrolling the table, the object value associated with a given row of views is changed to that the views in the row will display different content

What is the difference between beginTrackingWithTouch and touchesBegan?

Can someone please explain the high-level difference between these two methods? In particular, when would you use one over the other, and is there any overlap in terms of the purposes of these methods?
They seem like they serve the same purpose but don't appear to be related at all in documentation, and this has me confused.
beginTrackingWithTouch:withEvent:
1) subclass UIControl
2) Sent to the control when a touch related to the given event enters the control’s bounds.
3) To provide custom tracking behavior (for example, to change the highlight appearance).
To do this, use one or all of the following methods: beginTrackingWithTouch:withEvent:, continueTrackingWithTouch:withEvent:, endTrackingWithTouch:withEvent:
touchesBegan:withEvent:
1) subclass UIResponder
2) Tells the receiver when one or more fingers touch down in a view or window.
3) There are two general kinds of events: touch events and motion events.
The primary event-handling methods for touches are touchesBegan:withEvent:, touchesMoved:withEvent:, touchesEnded:withEvent:, and touchesCancelled:withEvent:.
The parameters of these methods associate touches with their events—especially touches that are new or have changed—and thus allow responder objects to track and handle the touches as the delivered events progress through the phases of a multi-touch sequence.
Any time a finger touches the screen, is dragged on the screen, or lifts from the screen, a UIEvent object is generated. The event object contains UITouch objects for all fingers on the screen or just lifted from it.
Having just run into this today, I think the key difference is that beginTrackingWithTouch and friends are only for tracking - not anything else - in particular not for target/action handling. So if you override touchesBegan, then you'd also be responsible for calling sendActionsForControlEvents when touches ended. But if you use beginTrackingWithTouch, that's handled for free.
I discovered this by implementing beginTrackingWithTouch (for a custom button control) thinking it was just a sideways replacement for handling touchesBegan. So in endTrackingWithTouch, I called sendActionsForControlEvents if touchInside was true. The end result was that the action was called twice, because first the builtin mechanism sent the action, then I called it. In my case, I'm just interesting in customizing highlighting, so took out the call to sendActionsForControlEvents, and all is good.
Summary: use beginTrackingWithTouch when all you need to do is customize tracking, and use touchesBegan when you need to customize the target/action handling (or other low-level details) as well.
If I properly understand Apple documentation:
beginTracking:
Use the provided event information to detect which part of your control was hit and to set up any initial state information
So, it's more for control state configuration.
touchesBegan:
Many UIKit classes override this method and use it to handle the corresponding touch events
This method is more for touch event handling.

Memory limit to number of items in table view

Is there a memory issue regarding the number of items in the list I am displaying in my table view? If the user keeps adding items will the application eventually crash or something due to memory issues?
To answer your questions:
There's no black and white answer to this. To try my best to explain, think of UITableView as sort of like a visual data array. In fact, most people (myself included) use a source data object like an NSArray or an NSDictionary to provide the display data for a UITableView. All the memory limitations that would apply to these objects (arrays and dictionaries) apply to your UITableView, assuming your UITableView is set up properly and you're using the recommended techniques for reusing cells. What this boils down to is: Is it possible to have a very large UITableView? - Yes. How long though, this I don't know. I've created UITableViews with complex subclassed cells and 200 rows and they worked fine. It depends on how you set up the table and the data source you're using. Bear in mind again that the limitation is due to the data source. Have an extremely large array and eventually your device will throw a memory warning. As a best practice, use pagination. There are tonnes of tutorials online to enable paging on UITableViews. Lazy load your images (if any) if they are being downloaded.
Yes you can. You can do lots of amazing things if you're creative enough while subclassing UITableViewCells. Otherwise, you can use the standard UITableViewCell as well. There are two labels on there: The textLabel and the detailTextLabel. Use these two to display the data you want.
Your UITableViewDelegate has a didSelectRowAtIndexPath method which you can implement. As long as your view controller housing the UITableView is set to be it's delegate, it will respond to didSelectRowAtIndexPath.
Just empty the array you're using as a data source (bear in mind that your numberOfRowsInSection data source method MUST use the array count) and call reloadData on the UITableView
EDIT: The question got edited, so only point 1 from the above 4 points applies to the question :) The others are nice to know though
Nothing table-specific, but yes, you will run out.
The most important thing is probably to use dequeueReusableCellWithIdentifier: in your tableView:cellForRowAtIndexPath: delegate method. This basically cuts down memory usage to the number of visible cells (plus one being scrolled into view).

Fade continuously between two CAGradientLayer color set-ups?

I want a UIButton to pulse, and I plan to do this by fading slowly between two color arrays on a CAGradientLayer. Is there a way to repeat an animation back and forth?
Yes. In Core Animation you create an explicit animation to do the fade and then you must also set two other properties for the animation object: autoReverses and repeatCount (number of repetitions to perform, each 2 repetitions will take you through your animation and back again). In your case you’d add the following lines to your code that sets up the animation object (I’ll call the object anim):
anim.repeatCount = HUGE_VALF;
anim.autoReverses = YES;
HUGE_VALF causes the animation to repeat forever though you could specify a number larger than any amount of repetitions that might occur.
These properties aren’t shown in the documentation of the CAAnimation object or it’s subclasses since it is defined in the CAMediaTiming Protocol which is adopted by CAAnimation and it's subclasses. But you can see examples and discussion of the CAMediaTiming protocol as it applies to CAAnimation objects in the Timing, Timespaces, and CAAnimation section of the Animation Types and Timing Programming Guide either on Apple’s Developer site or in the documentation provided through XCode.
(Many people seem to find Apple's Core Animation documentation to be particularly hard to understand until you get a good overall grasp of the disparate parts. I basically knew what you had to do but still found it hard to remember exactly where to find the actual information as to the properties involved.)

Fitting Cocoa Animation into MVC/OOP patterns

MVC/OOP design patterns say you don't set a property, per se, you ask an object to set its property. Similarly, in Cocoa you don't tell an object when to draw itself. Your object's code has detailed HOW it will draw itself so we trust the frameworks to decide when (for the most part) it should draw.
But, when it comes to animation in Cocoa (specifically Cocoa-Touch) it seems that we now must take control of when the object draws itself from within the objects view controller. I can't send a message to a UIView subclass asking it to change some value and then leave it alone knowing it will slowly (duration = X) animate itself to a new position, alpha, rotation, etc. depending on the property changes. Or can I?
Basically, I'm looking for a way to set the property and then walk away. Instead, it seems, I need to wrap the code that calls the object asking it to change its property with an animation block of some sort "[UIView beginAnimations:nil context:NULL]; ... [UIView commitAnimations];"
I'm ending up with lots and lots of animation blocks in my view controllers and none in my view objects...I guess I'm just looking for someone to verify that this is how things are done and I'm not overlooking something. I haven't gotten much farther than the UIView animations within Cocoa-Touch, so maybe that's my problem and it's time to dig deeper?!?
You are correct that UIView does not animate its property changes by default the way CALayer does, but I don't think this indicates a break in MVC. It is appropriate for a Controller to instruct a View in how it should transform. That is the role of a Controller class as surely as it is appropriate for the Controller to know the correct frame for the View and even manage layout. I agree that it's a little weird that you call -beginAnimations:context: on the UIView class rather than on an instance, but in practice it does actually work much better that way since you may want to animate many views together.
That said, if you had a UIView subclass that managed the layout of its subviews, there would be nothing wrong with allowing that UIView to manage the animation rather than relying on a UIViewController to do it. So this is something that could go either place, but in practice it generally goes in the Controller as you've discovered.
I am using "MVC" here in the typical Cocoa sense. You're correct that this might not be appropriate in a SmallTalk program, but then SmallTalk Controllers have a much more limited role (management of user input events). Cocoa significantly expands the role of Controllers in MVC and I think it's an improvement, even if it means there are now some functions that could go in either the Controller or the View (and this is one of them).