Template for preloading data for later viewing

A very simple use case. Let's say an iOS application displays a MovieListController (inside a UINavigationController ) with a list of movies. When a user touches one, the application pushes the MovieDetailController the navigation stack (ie [[MovieDetailController alloc] initWithMovieId:(NSString *) ). In the MovieDetailController method MovieDetailController viewDidAppear: it makes an HTTP call to retrieve the details based on the identifier of the movie passed to it.

The task is that the MovieDetailController immediately gets on the navigation stack, and for a second or two, until the details have been received, the view shows empty empty fields, which is undesirable.

To get around this, I think that MovieListController does not push the MovieDetailController onto the stack right away. Instead, he set a progress indicator (I use SVProgressHUD), and then call the MovieDetailController initWithMovieId: , which will trigger an HTTP call. Then, when the data is received, MovieDetailController will revert back to MovieListController to remove the progress indicator, and then push MovieDetailController on the navigation stack.

Is there a better template for this type of scenario? Should I consider pushing the MovieDetailController button on the navigation stack when it is ready?

Note. I looked at loading a detailed view and displaying an activity indicator, but you can still see the “empty view”, which looks a little strange. I also thought that only MovieListController retrieves the data itself, but this seems to violate the encapsulation model. MovieListController should simply be related to the enumeration of movies, not their details.

Any thoughts? This film is just an example - finding the big picture here.

+4
source share
3 answers

In this situation, I will personally return to the model-view-controller template.

There are several system applications that display a detailed view from a list of objects, for example. Calendar, Contacts, etc. Presumably, as in EKEvent and ABPerson in the respective applications, the main view controller maintains a list of model objects. When the user selects one of the elements, the main view controller passes the selected model object to the detail view controller. The detailed view controller itself is not required to download data. So, as @ChrisWagner said, we want to separate the logic from the view controller.

Method

Similarly, you can use the MovieList class, which stores an array of Movie objects. Each Movie stores the values ​​for all fields in the detail view controller — essentially all the information the application needs for the movie. For example, you might have the NSString *movieTitle or NSDate *premiereDate property. movieTitle would be set by MovieList on initialization, because it is only metadata; on the other hand, premiereDate may be nil if the data is not loaded, so you have the BOOL isLoaded property to check this condition.

Then you can do one of two ways:

1) Say that the main view controller wants to click the detail view controller for the movie. The main view controller then subtracts the Movie from the MovieList and checks to see if it is loaded. If not, then on Movie. something like -(void)loadContents will be called. When the model object is finished, it will send a notification that the download is complete. At this point, the main view controller will reject its progress view and click the detail view. If you use (1), it is not so important to use the MovieList coordinator.

2) If you want to load movie information more aggressively, you can implement a method on a MovieList that calls loadContents on a Movie in the background. Then there is a higher probability that the film will already be downloaded when the user selects it.

Change Please note: if you decide to use an object of type MovieList , access to this list should be allowed only to the main controller. In some ways, the structure of the model that I described is parallel to the structure of the view controller. The detail view controller does not know about the list view controller, so it should not know about MovieList .

Benefit

The advantage of using this Movie and MovieList is that the data model is completely separate from the view controllers. In this way, the user can cancel, select, submit and reject view controllers during data loading. (Imagine if the user clicked Back to cancel the HUD progress by canceling any HTTP data that he would have collected. Then, if he decides to return to the same movie, the new details view controller should start downloading again.) Also, if you decided to replace the classes of the class controller during the development process, you do not have to copy and paste a bunch of data processing code.

I think you will find that structuring your application in this way not only gives you and the user more freedom, but also makes your application effective and open for future extensions. (Sorry it's so late, but I wanted to include MVC in this template-related discussion!)

+2
source

Personally, I would take the following approach.

  • The user selects the movie that they need, for
  • Click on the detailed view and instead of showing your skeleton with empty fields, overlay a loading image on it, you can continue to use your HUD progress on top of this for any animations you get with it.
  • Once the results are lowered, remove the HUD and overlay image that hides all data / fields

The reason that I will go along this route, instead of showing the HUD before clicking the view controller, is that you can give the user the opportunity to cancel their choice. I am not familiar with SVProgressHUD , but hopefully when the HUD is displayed, you can enable touches, especially the user touching Back on your UINavigationController , in case they accidentally select a movie, or the request just takes longer than they want to wait.

It also separates the logical form from your list, your detailed view is autonomous and can be initialized anywhere in your application (maybe you want to cross-link similar films in the detailed view of the movie), and you don’t need to rewrite the logic of the view waiting for the results to return .

+5
source

I think a more advanced route would be to run detailed queries when cells are displayed in the tableview / collection view. Then, when the cells are moving overs, cancel the queries. You can download movie details unnecessarily, but I don’t think it’s very important because you only fill in your db with movie details that you might not need, and coredata can handle this. This assumes that your api requests occur in the bg stream and they do not affect the main (UI) stream.

+1
source

Source: https://habr.com/ru/post/1487576/


All Articles