From the UIPageViewController template provided by Apple I'm working on creating a digital block calendar, meaning that the app will consist of 365 pages of content, and when it opens I want it to show the page according to today's date. Now I'm quite familiar with NSDates and such, but much less with the UIPageViewController. Before getting myself into unnecessary trouble, what would seem the most straightforward way of accomplishing this?
I would recommend using this gitHub project called RTSPagedView. First, it will dequeue and reuse views, so you only have a few views in memory (not 365). As a view appears, it dequeues like a UITableView, and fills the next offscreen view with the next index of data in your array.
Second, use the setContentOffset method to scroll to a particular date (pageWidth * index). However, you might want to play with that 365 threshold. My guess is you could get away with something like 30 in cache, and load a new data source as the user gets close to an edge of your dates.
RTSPagedView: http://github.com/rplasman/RTSPagedView/
Related
I crating project to play with some sort of simulation. So i create map, this map is actually grid with cells, each cell is 2 actors - 1 background and 1 icon that show cell type - forest, mountain, person and etc.
Here how it looks:
All works just fine, but when i try to increase cells from 20x20 to 100x100 it takes about 20-30 seconds to load. It doesn't seems lags after it loads, so it works just fine, but now question - is there a way to optimize loading time, or it impossible?
Todays systems should be able to handle as little as 100x100 cells. I guess your problem is somewhere in your code.
Some common mistakes are:
Creating new objects in your render method (with the "new" keyword) instead of reusing your objects
Loading your images everytime you render them
Maybe you can add some code of your render method to the question. Without any code it's hard to see the problem.
In relation to How to determine if a user has scrolled to the end of an NSTableView
Thanks Josh.
Is there a way to use this mechanism to implement a NSTableView that provides some sort of infinite scroll or pagination.
The idea is to tell NSTableView to load up to a certain number of records, say 1k records at once and than as user scrolls closer to the end pull another 1k records and maybe forget the first 1k records.
This pattern is well defined/used in web applications and java. Only the visible number of rows is loaded initially and the rest is pulled async as user scrolls up and down the table.
I am interested in some obj-c code or tips on how to code this.
I know about filtering/limiting the number of records that go into the tableview but lets ignore that for a moment.
Thanks.
Given the details you've provided, I'll generalize a bit but here's how I might solve it:
First, I'd set a MUCH SMALLER batch size than 1000 records. If the result count or "the most anybody is ever going to want to see" is indeterminate (and it sounds like it is in your case), the user probably doesn't even care past the first 100 or so. If your user often requests a large, expensive list and immediately wants to see stuff so far away from the beginning they hurl the scroller downward for two minutes straight before they stop and look around, perhaps a more intuitive sort order is needed instead of asking Google Image for 1000 more animated kitten gifs. ;-)
The controller behind the (definitely view-based for view reuse) table view will need some sort of request queue since I assume you're batching things in because they're expensive to retrieve individually. This will manage the asynchronous requesting/okay-now-it's-loaded machinery (I know that's vague but more detail is needed to get more specific). You'll make sure any "currently alive" views will somehow get this "it's ready" notification and will go from some "busy" UI state to displaying the ready item (since we NEVER want to keep the table waiting for a ready-to-display view for the object at a given row, so the view should at least show some "still waiting for details" indication so quick scrolls over lots of rows won't stall anything).
Using a view-based NSTableView and associated data source methods will let the table view handle only keeping enough copies of your custom NSTableCellView around to reuse during scrolling. Since you have to provide a configured view when asked, the view's default state can either be "draw nothing if not ready" or some visually generic placeholder until the object is realized and ready (then you can just reload that row instead of the whole table). This way the table keeps scrolling and drawing rapidly because it doesn't care about what your controller is doing to fulfill the promise of updating the visible rows (that custom cell view of yours will observe its represented object's updates).
You probably want the scrollers to reflect the total number of rows batched in so far if the upper bound is astronomical - reflecting that size would make the scroll grip both tiny and very sensitive. Instead, just grow the scroller (via the table view's row count) by what the user has "requested" so far, all the way back to the beginning of the list. Any time more are batched in, you'll want to add the batch size to your controller's total batched row count. This still lets the scroller zoom by rows the user couldn't distinguish at that speed anyway. You communicate the row count change to the table view by sending it -noteNumberOfRowsChanged and replying to its resulting data source request ( -numberOfRowsInTableView: ) with the updated total row count you stashed in a property of your controller. It'll ask for views for the newly visible rows as needed (which will be in some neutral, unfulfilled visual state until it's realized as before), update the scroll view, lather, rinse, repeat.
You could use NSCache to keep memory usage low. Set its countLimit to several times your batch size and let it drop previous batches if it decides it needs to dump the first n model objects, then batch them back in if the table view suddenly asks for a view for a row no longer in the batch window's range.
Without knowing more about your requirements and architecture, it's hard to get more specific. If I haven't hit the mark, consider editing your question to include more detail. If I'm totally off base from what you're asking for, please clarify. :-)
I know more about iOS, but I think the answer is similar. Table views are intrinsically finite, but you can roll your own custom scroll view to do this. The trick is to set a large content size and implement layout in your subclass (which will get called on every scroll change). In that method, check to see if the content offset is near zero or near the content size. If it is, then translate the content offset back to the center of the content size and translate all the subviews (keep them on one parent content view) by the same distance so the user doesn't see any motion. Make a datasource protocol and keep asking your datasource for "cells" that tile the visible part of the view.
It should be up to the datasource to recognize what we would have called a page-fault in the olden days, to decide that some of the model in memory should be discarded in favor of the model where the user is scrolling.
I poked around for an NS equivalent, but didn't see one on cursory search. Here's a decent-looking reference on the idea done in iOS.
I have already sort of asked this question already here (Previous Question) but it only got a handful of views and zero answers/comments so I thought I'd give it a go again with some more info that I've found.
I basically have a Windows Store DirectX + XAML app that I'm developing. I currently have the problem that the Rendering event of the SwapChainBackgroundPanel that I use for DirectX rendering (as per the Windows 8 example on MSDN) sometimes isn't called when the user is interacting with the app.
It will continue to update if I am doing something with the camera such as changing what it's looking at based on touch/mouse position but it won't be called if I am picking and I don't know why.
I use the standard GPU picking method (where I render the scene with a unique color for each object and then take a 1x1 texture of the press area to find the selected object) but when I am using this picking technique to select multiple objects (the user drags their finger/mouse over many objects) Rendering isn't being called. So in effect what happens is, lots of objects get selected but the user only sees this when they remove their finger/stop pressing the mouse button.
Is there any reason why this is happening? Is it because of the GPU picking method? And if so is there a way around it rather than using the ray-trace picking method (which considerably slows down picking for a large number of objects)?
Has anyone else had this problem? Is there an explanation from Microsoft anywhere that it is deliberate that rendering doesn't get called while this is happening?
Thanks for your time.
I need to create a iOS app where the main screen is very similar to the Facebook iOS App. I am using a UITableView to show the different posts in the feed. My question is:
What is the best option to implement this? One option is to insert Textviews/Imageviews/labels to the table view cell and another option is to have one UIWebView in each table view cell.
I have to show a lot of pictures and texts, so maybe html will be easier.
Any experience?
If you have to show a lot of pictures and text, adding one complexity level (like HTML) is not gonna help.
I'd suggest to start researching on how you can speed that huge table up, and how to retrieve the content you want to display on each cell. For instance, you could use a parallel thread that would retrieve the content in the background as you scroll down and would store it in a cache so it doesn't have to be done several times. RestKit or (depending on your specific needs) AFNetworking are surely of some help in your case.
Also, have a look to this article (a bit old, but still interesting!) on how improve your scrolling speed: Fast scrolling (and link to github example project)
First of all, I know there are a few other StackOverflow questions about this subject, but I have read them all and I still am confused about what to do for my situation. I'm probably missing something obvious here, if you could help clarify that would be much appreciated!
I have a app which is doing a lot of work to animate images within a view - mainly comprised of a number of images moving in straight lines for a second or two at a time. I considered at first making them all simple, once off animations using UIView animateWithDuration for the whole duration of the movement. But I found that didn't give me a lot of power to intercept the movement or stop it or check where it was up to, so I scrapped that. My new approach is to use an NSTimer, firing 20 times per second, doing incremental movements. This way I also can intervene (almost) instantly to change the animation or stop it or update a status label based on how far through it is, etc, etc.
First of all...there probably is a better way than this. Feel free to suggest something better!
Assuming this is acceptable though, my issue now is that while these animations are happening, I can't click any of the other controls on the UI. I get no response. It's not like it's just slow or delayed either - the click never comes through. It seems that the NSTimer processing totally locks the UI - but only from new interactions. Changes I make to the UI within the timer processing method happen just fine, and are very snappy.
From what I've read this shouldn't happen. However I also saw a comment on this question saying that if the timer processing is intensive then it could lock the UI thread. I don't see my processing to be that intensive here - certainly no resource requests, just a bit of data manipulating and animating some objects - but I could be underplaying it.
What are my options here? At first I thought I might create a new thread to kick off the timer. But I remember reading that the UI updates have to happen on the main thread anyway. Why is this? And plus, would that really solve the issue? Am I just asking too much of the device to process this timer as well as UI interactions? Is there something else I'm missing?
Any and all advice would be appreciated.
Edit:
I've just found the cause of my UI blocking problem. I was using the animateWithDuration with blocks, but was not setting the options. Therefore UIViewAnimationOptionAllowUserInteraction was not set. I changed it to set this option and my UI is happily responding now.
That said, I'll still leave this question open for specific suggestions regarding my overall approach. Thanks.
I would consider using CADisplayLink. From the documentation:
A CADisplayLink object is a timer object that allows your application to synchronize its drawing to the refresh rate of the display.
Your application creates a new display link, providing a target object and a selector to be called when the screen is updated. Next, your application adds the display link to a run loop.
Once the display link is associated with a run loop, the selector on the target is called when the screen’s contents need to be updated. The target can read the display link’s timestamp property to retrieve the time that the previous frame was displayed. For example, an application that displays movies might use the timestamp to calculate which video frame will be displayed next. An application that performs its own animations might use the timestamp to determine where and how displayed objects appear in the upcoming frame. The duration property provides the amount of time between frames. You can use this value in your application to calculate the frame rate of the display, the approximate time that the next frame will be displayed, and to adjust the drawing behavior so that the next frame is prepared in time to be displayed.
Your application can disable notifications by setting the paused property to YES. Also, if your application cannot provide frames in the time provided, you may want to choose a slower frame rate. An application with a slower but consistent frame rate appears smoother to the user than an application that skips frames. You can increase the time between frames (and decrease the apparent frame rate) by changing the frameInterval property.
When your application finishes with a display link, it should call invalidate to remove it from all run loops and to disassociate it from the target.
CADisplayLink should not be subclassed.
I'm not totally sure how everything is handled in your program, but you might want to just consider having one thread/timer that controls all of the objects and their movements. There's really no need to create a separate thread/timer for every single object, as that will easily cause problems.
You can just create a class for your moving items with some variables that contain information about their direction, speed, duration, etc, and then have a controlling thread/timer calculate and move the objects. You can then intervene onto the one main controller object instead of having to deal with many other objects.
I think you'll find that even if you optimize this, timer based animation like this is not going to perform well.
You might want to ask about the specific things that you think you couldn't do with CoreAnimation. If you solve those issues, you'll end up with a much better result than trying to roll your own.