Is creating an NSString or NSArray expensive? - objective-c

I'm working on optimizing the performance of my TableViews, and was wondering how expensive it is to create simple objects like a string or array within cellForRowAtIndexPath. The other option, of course, is to create the object as an ivar and set it each time a new cell gets loaded.
Which is better, creating a new object for each cell, or resetting the same object for each cell?
Note: I'm using these objects to do a number of different things, for example I'm creating a string to check the length of text I'm downloading from a server before passing it to the cell.

Creation of simple strings and arrays is not going to have an effect on the performance of your table. Creating views is expensive, and drawing them is also expensive - these are the areas you need to optimise for good scrolling.
Profile in instruments using the time profiler and core animation FPS instrument to be sure. This will highlight hotspots in your code, or alternatively give you a 60fps scroll rate*, in which case your work is done!
*on the device, of course

Related

Issue in lazy loading the table view

I am badly struck in a issue where I am trying to populate the nestableview lazily. Below is my approach.
I have created a custom class PRIList where it has an instance of array to manage the models.
I have bound the priList.items to the array controller in the xib where items is not an instance in PRIList but to support lazy loading I have implemented the methods countOfItems and objectInItemsAtIndex:.
Initialy when I populate the PRIList I populate few objects (say 50) with valid objects and rest with the faulty objects. In the objectInItemsAtIndex I check if the item at particular index is valid or faulty. If it is faulty I fetch next set of 50 objects.
What I understand is NSArrayController calls the method objectInItemsAtIndex for only the visible rows in the table view. But the problem here is as soon as set the PRIList the objectInItemsAtIndex method is called for all the objects. This is even called when some selection is changed in table view (the stack trace shows this method is called from [_NSModelObservingTracker startObservingModelObjectAtReferenceIndex])
Basically I want to fetch the records whenever the user scrolls down in the table view.
I followed the same approach in a different project in Lion. It worked there. Currently I am in Mavericks.
I tried overriding the isCompatibleWithResponsiveScrolling in the custom table view and returned it to NO. Still no luck.
Any help is very much appreciated.
First, have you assigned or bound the sort descriptors of the array controller? Or set any columns to automatically generate sort descriptors? (I'm not sure that latter is relevant. It depends on whether the column is sorted by default.)
In any case, if the array controller feels the need to sort the objects in order to arrange the objects, then it will need to load all of the contents. I was under the impression that it always does so, anyway, although you report that it works.
For an issue like this, I'd recommend that you go for full manual control. That means not using bindings or an array controller. Use a data source.

Fundamental Drag And Drop In iOS

I've been considering an app now that implements a drag and drop sort of idiom from maybe a side pane or a drawer, etc. what I can't wrap my head around are how to keep reference to the objects I drop. I mean; it would be easy if it was just drop the object, then let it alone, but I want more manipulation after the fact.
My brain just cannot wrap around the concept of creating objects out of thin air to place on the 'canvas', or having preset objects (which I imagine would be limited, cumbersome and awkward) already on the canvas that would then just be activated and manipulated easily, seeing as the references to them are created before the fact (my apologies for the loose term 'reference', I mean something like selecting the object and having it's unique properties recognized or displayed).
There must be something I'm missing. So, I wonder how one might go about implementing drag and drop with interface and manipulation with the dropped object after the fact or maybe sample code or a link to a git or svn repo? (something like how MIT's scratch, or Xcode's interface builder might work).
For clarity's sake, I know how to go about fiddling with drag and drop thanks to DragKit, but not about editing 'properties' on the object dropped onto the 'canvas', and I would like there to be a near infinite amount of objects that can be dropped on the canvas, yet a set amount of items in the drawer/side view.
If I'm understanding your question correctly, you want to be able to drag objects onto a canvas and then manipulate their properties individually. For instance, you'd drag square views onto the screen and then increase its size or change its color.
In order to do something like that, I would have a NSMutableArray or an NSMutableSet that would hold all of the on canvas objects. Then when any interaction comes, you could either dynamically generate gesture recognizers if the objects are UIViews or a subclass. Then in the target of the gesture recognizer you would use the recognizer.view property.
Or you would have to check which object on the canvas you were currently manipulating. That would be done by iterating through the array and seeing which object equals the one you are touching.
Is there anything that you are trying to do but is not working? Have you written any code in attempt to do this?

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).

Working with many interface elements in Cocoa

My app requires an interface that has many buttons, text fields and matrixes. And they need to change from time to time. Right now I do this by having all elements in IB already and hiding/showing/moving them when needed. What would others recommend? Should I do that? Should I use an NSTabView? NSView? Should create the elements programatically? If so, what if I have an element that is already created that I need again without changes? It would be a waste of releasing it and creating it again.
Any help would be greatly appreciated.
In my opinion, it's better to create interfaces programmatically if you have to animate views around a lot. If it's just a matter of hiding/unhiding them, IB works great, but if you need re-layout or create unknown numbers of views dynamically it's not worth trying to make it all work with nib files.
As for general advice:
Create subclasses (from UIView or UIControl or one of their subclasses) for every kind of element you're going to use. It's tempting to piece together composite views from your UIViewController, but you'll really be much better off creating real classes.
Study the standard Cocoa view classes, and try to create similar API:s in your own controls and views.
Put as much data (sub-element positioning etc) into a plist, so that you can easily change it from one centralized place instead of having to dig around in the code.
If you are often creating several dozen short-lived views, it's worth keeping them in a pool and reusing them. But if it's just a few labels being added and removed intermittently I wouldn't worry too much about it. As usual: don't optimize too early.
Your current approach sounds fine. If you're showing/hiding them but otherwise they remain unchanged, why go through the trouble of creating them with code, when your XIB keeps a "freeze-dried" copy of exactly what you need already?
As long as you're keeping them within logical groups, you can just move/swap/show/hide the group's container (like NSBox or an NSView). If you have a LOT of logical groups, which aren't always shown every session, you can separate them out into their own XIBs and only load them when they're needed, to save launch time and memory.
If you use NSViewController, it's even better because you can make clean breaks for each logical group. Load the panel as the view and the view controller will keep outlets/actions and has a one-to-one relationship with a xib.

Slow loading of UITableView. How know why?

I have a UITableView that show a long list of data. Use sections and follow the sugestion of How to solve slow scrolling in UITableView .
The flow is load a main UITableView & push a second selecting a row from there.
However, with 3000 items take 11 seconds to show. I suspect first from the load of the records from sqlite (I preload the first 200). So I cut it to only 50.
However, no matter if I preload only 1 or 500, the time is the same.
The view is made from IB and all is opaque.
I run out of ideas in how detect the problem. I run the Instruments tool but not know what to look.
Also, when the user select a cell from the previous UITable, no visual feedback is show (ie: the cell not turn selected) for a while so he thinks he not select it and try several times. Is related to this problem.
What to do?
NOTE: The problem is only in the actual device:
iPod Touch 2d generation
Using fmdb as sqlite api
Doing the caching in viewDidLoad
Using NSDictionary for the caching
Using a NSAutoreleasePool for the caching part.
Only caching the row ID & mac 4 fields necesary to show the cell data
UIView made with interface builder, SDK 2.2.1
Instruments say I use 2.5 MB in the device
The -[FMResultSet next] call can be a very expensive call to make, depending on the data that's getting loaded. It'd during this call that sqlite is actually going to the database, finding the next row to return, and giving you back the appropriate fields. It's not just an enumerator.
You might want to consider pre-caching all of the data before actually displaying the table. This means that you would do all of your FMDB calls before the table gets shown on the screen.
If that takes too long, you might want to show the tableview with its initial rows, and then use NSOperations or just a second thread to load the data in the background and cache it that way.
Without seeing any code, I think I would be inclined to think that you need to index you tables.
You should see an enormous speed up by adding an index on the attributes you query on. You can do this by using the CREATE INDEX SQL command.