Upload a video to a UICollectionViewCell with a background thread to create a seamless scroll

I am working with an Objective-C application that has a scene with full-screen horizontal scrolling UICollectionView. I currently have a function called every time a new cell appears on the screen during scrolling, which takes about 3-4 seconds to start and edits ui elements in a newly appeared cell. Because of this, my application is delayed every time a new cell enters the screen for about 4 seconds, and then continues to scroll normally.

Is there a way to edit this function and put it in the background thread so that instead of scrolling in 4 seconds it scrolls continuously? I understand that this solution will cause a 4 second delay in the appearance of ui elements, but I am fine with this if there is a seamless scroll.

EDIT: I did not think it would be nice to publish the code for this problem, since the function loaded into the program requires the video game api that I bought, but I will continue and send the method below to show which parts of the function are editing the user interface.

//variables declared in other parts of the file KolorEyes *myKolorEyesPlayer; UICollectionView *collectionViewFollwersFeed; NSIndexPath *lastPath = nil; //called repeatedly while scrolling -(void)scrollViewDidScroll:(UIScrollView *)scrollView{ if(scrollView==_collectionViewFollwersFeed) { [self tsLoad]; //function call } } - (void)tsLoad { //calculate index path of cell in the center of the screen NSIndexPath *centerCellIndexPath = [self.collectionViewFollwersFeed indexPathForItemAtPoint: [self.view convertPoint:[self.view center] toView:self.collectionViewFollwersFeed]]; if(centerCellIndexPath != lastPath) //condition is satisfied if a new cell has been scrolled to the center { lastPath = centerCellIndexPath; UICollectionViewCell *cell; NSString *CellIdentifier; //initialize cell from center path CellIdentifier = @"FollowersFeed"; cell = [_collectionViewFollwersFeed cellForItemAtIndexPath:centerCellIndexPath]; //get respective url for video player NSMutableDictionary *dict1=[follwerFeed objectAtIndex:centerCellIndexPath.row]; NSString *tsstring= [dict1 valueForKey:@"video"]; NSURL *tsurl = [[NSURL alloc] initWithString:tsstring]; //view that the video will be played in UIView *tsView = (UIView *)[cell viewWithTag:99]; //API-specific parameters for video player session KolorEyesSessionParams *params = [[KolorEyesSessionParams alloc] init]; params.delegate = self; /* other params properties set like above at this point... ... ... */ //API-specific initialization myKolorEyesPlayer = [[KolorEyes alloc] initWithParams:params]; //API-specific parameters for video player view KolorEyesRenderViewParams *fparams = [[KolorEyesRenderViewParams alloc] init]; fparams.cameraFieldOfView = 90; /* other fparams properties set like above at this point... ... ... */ //API-specific initializations id _tsViewHandle = [myKolorEyesPlayer setRenderView: tsView withParams:fparams]; [myKolorEyesPlayer setCameraControlMode:kKE_CAMERA_MOTION forView:_tsViewHandle]; __block KolorEyes *player = myKolorEyesPlayer; //error checking eKEError err = [myKolorEyesPlayer setAssetURL: tsurl withCompletionHandler:^{ // Media is loaded, play now [player play]; }]; if (err != kKE_ERR_NONE) { NSLog(@"Kolor Eyes setAssetURL failed with error"); } } } 
+6
source share
4 answers

You can define an “ NSOperationQueue ” to trigger background operations, and when the cell is visible, you can load the video into the UICollectionView cell.

Also, be sure to use NSOperationQueue and call " cancelAllOperations " when the View collection is no longer required.

+2
source

Is there a way to edit this function and put it in the background thread so that instead of a 4 second lag in the scroll there is a seamless, continuous scroll?

You are using the SDK as you mention:

Kolor Eyes is a free 360-degree sphere video player application with accurate pixel projection algorithms. The user can select different camera points of view at any time using touch gestures or motion control devices. This is more than a player, it is an ideal browser designed for Kolor 360 video hosting. This documentation applies to Kolor Eyes iOS from version 2.0

There are enough problems starting Apples in the native “AVPlayer” in the UICollectionView / UITableView without delay, and you want to start the 360 ​​custom video player without any delay.

Since this is an SDK, you cannot access and / or modify any code , you need to contact the developers of the SDK for recommendations. I don't think this SDK is designed to work in scrollView in mind, as it seems to be a difficult task (I'm not 100% sure you need to ask the developers).

However , you should not change the user interface in the background thread as you ask that it doesn’t help the lag leave, it will make it worse and even crash or hang your application in most cases, and I’m sure (at least least) that developers make as many threads as possible using this SDK:

In a Cocoa application, the main thread launches the user interface, which all drawings and all events are processed in the main thread. If your application performs any lengthy synchronous operations on this thread, your user interface may stop responding and cause a rotating cursor. To avoid this, you should reduce the time consumed by these operations, delay their execution or transfer them to secondary threads.

Source

0
source

In theory, you are right. You should be able to download a video that is not related to the user interface (for example, download a video) in the background stream, and send the main stream when you really want to display it. In practice, I have found that it is very difficult with many third-party libraries. Most video libraries expect to be fully launched in the main thread. You will need to check with your sdk video - but I would be surprised if they supported background downloads.

Another solution is not to load the video in cellForItemAtIndexPath: but instead load the video for the visible cell when scrolling. You can track delegate scrollViewDidEndDragging and / or scrollViewDidEndDecelerating .

0
source

Oh, I tried playing the video while scrolling before. I did not do it then. When you did this, you probably saw my question about this, since this is most of the same logic? In the end, I started playing the video when the scrolling stopped, but that was a long time ago, and I am no longer working on it.

Now I may have an idea for you.

Before diving into it, I just say: this one works , but I'm not 100% sure if it will work for a video game. You have to find out. I apologize for this, but it can be quite difficult.

It completely depends on your situation with the number of cells, etc., you may be interested to disable cell reuse and just recompile everything.

I have not done this in UICollectionViewCell , and I don't know what KolorEyes , but it will probably work for UITableViewCell and AVPlayer , although I don't have time or will check it. I will try to explain the logic of what I think.

I did not do any Objective-C , so I will do it in Swift , but I hope you understand what I think: First make this class:

 class PrecompiledCell{ var cell:UICollectionViewCell? = nil var size:CGSize? = nil // constructor and such } 

This class is just a wrapper for your cell. Now you must create one instance of PrecompiledCell for each cell that you will display, I. One for each followerFeed file. You must make a function called precompileCells() and call it whenever you update your data source ( followerFeed ). This function should traverse all the elements of your follwerFeed -array and create one cell for each. Like your cellForRowAtIndexPath , perhaps today.

 var followerFeed:[[String:Any]] = [] // Your data. Probably an NSArray with NSDictionaries inside? var precompiledCells:[PrecompiledCell] = [] //Your array of precompiled cells func precompileCells(){ var precompiledCells:[PrecompiledCell] = [] for feed in followerFeed{ //Create the cell let videoCell = UINib(nibName: "MyVideoCell", bundle: nil).instantiate(withOwner: nil, options: nil)[0] as! MyVideoCell //Each instance of this cell (MyVideoCell) should already be initialising its very own KolorEyes-player etc., so now you can say this: videoCell.kolorEyesPlayer.setAssetURL(feed["video"]) //Of course, convert String to NSURL etc. first.. let precompiledCell = PrecompiledCell() precompiledCell.cell = videoCell precompiledCell.size = //Find out what size the cell is. Eg by using videoCell.contentView.systemLayoutSizeFitting(UILayoutFittingCompressedSize), or even easier if you have a constant size. precompiledCells.append(precompiledCell) } self.precompiledCells = precompiledCells } 

Now it’s important not to do this job twice. The whole idea of ​​this answer is that your regular cellForRowAtIndexPath (or scrollViewDidScroll in your case) should not do all this work when using scroll. The reason for the current delay is that the view initializes so many things while scrolling. With these precompiled cells, everything is already initialized before you can start scrolling. So, now remove the initializations and any deviations from your regular delegate methods and do the following:

 func collectionView(collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { return self.precompiledCells[indexPath.row].cell } func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { return self.precompiledCells[indexPath.row].size } 

When scrolling, there is no longer an initialization element, because everything has already been initialized before. The only thing you need to do now is use your old scrollViewDidScroll function, do the same as you (save the current index, etc.), and just put [player play]; and not other things.

Important thoughts

First, it is really important to call collectionView.reloadData() after self.precompileCells . Therefore, this should happen as follows:

 self.followerFeed = [/*new data*/] self.precompileCells() self.collectionView.reloadData() 

In addition, this implementation will completely disable dequeuing, which is actually bad practice as far as I know. Do not use this if you are loading a huge number of cells. Then try to break it a little.

This implementation may cause a delay in the actual precompilation, but rather than a delay in scrolling.

If you load swap cells (for example, scrolling to the end will load more cells), then you should really improve my code, as it will recompile all cells. Then you should do something like insertPrecompiledCells -thingy.

Once you have precompiled your cells, each cell can decide for itself whether it should start downloading the video. If they need to download the entire video, just a few seconds after the video starts or download it before you ask it to play at all. Running a partial load can be either asynchronous or a simpler start when scrolling.

I thought when writing this it might be a bad idea to have KolorEyes -player for each cell. You might want to have one single KolorEyes -player globally and just pass it to the correct cell - but , you can still compile the cell before setting up the video player, and you can also run the actual video asynchronously (without a player) (depending on what the hell is KolorEyes player, but you'll see that part of him ...)

Again, this is just an idea that might work. I used this for tableViews with complex cells to dramatically increase the smoothness of scrolling, but in a very controlled way (no more than 30 rows, etc.).

I still have ideas and thoughts about this, but this post is already too long, and I have to go now. Good luck

0
source

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


All Articles