From a2c3cca94b7ad53189fe1ae52dc1fda039efb87a Mon Sep 17 00:00:00 2001 From: Marco Schmickler Date: Thu, 31 Dec 2015 11:59:23 +0100 Subject: [PATCH] Prefetch Bulk --- kplayer/photo/MediaPhotoController.swift | 224 +++++++++++------------ kplayer/util/DataLoadOperation.swift | 19 +- kplayer/util/ImageLoadOperation.swift | 9 +- 3 files changed, 130 insertions(+), 122 deletions(-) diff --git a/kplayer/photo/MediaPhotoController.swift b/kplayer/photo/MediaPhotoController.swift index 0c010ef..a6ce3c1 100644 --- a/kplayer/photo/MediaPhotoController.swift +++ b/kplayer/photo/MediaPhotoController.swift @@ -7,7 +7,7 @@ import Foundation import Nimbus import Alamofire -class MediaPhotoController: NIToolbarPhotoViewController, NIPhotoAlbumScrollViewDataSource, NIPhotoScrubberViewDataSource { +class MediaPhotoController: NIToolbarPhotoViewController, NIPhotoAlbumScrollViewDataSource, NIPhotoScrubberViewDataSource, NSURLSessionDelegate { var items = [MediaItem]() var completionHandler: ((Void) -> Void)? @@ -21,29 +21,41 @@ class MediaPhotoController: NIToolbarPhotoViewController, NIPhotoAlbumScrollView var timer: NSTimer? - var currentIndex = 80 + var currentIndex = 100 - lazy var backgroundOperationQueue: NSOperationQueue = { - var queue = NSOperationQueue() - queue.name = "Thumb queue" - queue.maxConcurrentOperationCount = 10 - return queue - }() + var urlSession: NSURLSession? + + var sessionOwner = false + + let dateFormatter = NSDateFormatter() lazy var operationQueue: NSOperationQueue = { var queue = NSOperationQueue() queue.name = "Photo queue" - queue.maxConcurrentOperationCount = 6 + queue.maxConcurrentOperationCount = 3 return queue }() override func viewDidDisappear(animated: Bool) { - backgroundOperationQueue.cancelAllOperations() + operationQueue.cancelAllOperations() + } + + public func URLSession(session: NSURLSession, didBecomeInvalidWithError error: NSError?) { + print(error) } override func viewDidLoad() { super.viewDidLoad() + if urlSession == nil { + sessionOwner = true + let configuration = NSURLSessionConfiguration.ephemeralSessionConfiguration(); // backgroundSessionConfigurationWithIdentifier("imageLoad"); + configuration.HTTPMaximumConnectionsPerHost = 10; + configuration.timeoutIntervalForRequest = 100; + configuration.timeoutIntervalForResource = 200; + urlSession = NSURLSession(configuration: configuration, delegate: self, delegateQueue: nil); + } + imageCache.totalCostLimit = 1024 * 1024 * 1024 let backButton = UIBarButtonItem(barButtonSystemItem: .Cancel, target: self, action: Selector("back")) @@ -57,18 +69,69 @@ class MediaPhotoController: NIToolbarPhotoViewController, NIPhotoAlbumScrollView setChromeVisibility(true, animated: true) self.photoAlbumView.reloadData(); - self.photoScrubberView.reloadData(); - preload(0, count: 40) - preload(40, count: 40) + preload(0, count: 50) + preload(50, count: 50) + } + + func loadData(d: NSData, start: Int, end: Int) { + let bytes = Array(UnsafeBufferPointer(start: UnsafePointer(d.bytes), count: d.length)) + let string1 = NSString(data: d, encoding: NSUTF8StringEncoding) + print(string1) + var index = 0 + let fHi = (Int(bytes[index++]) << 24) + (Int(bytes[index++]) << 16) + let f = fHi + (Int(bytes[index++]) << 8) + Int(bytes[index++]) +// let f = (bytes[index++] << 24)+(bytes[index++] << 16)+(bytes[index++] << 8) + bytes[index++] + let time = dateFormatter.stringFromDate(NSDate()) + print("\(time) start \(start) count \(f) size \(d.length)") + + var rest = self.items.count - self.currentIndex + + if rest > 50 { + rest = 50 + } + + if rest > 0 { + self.preload(self.currentIndex, count: rest) + self.currentIndex += rest + } else { + dispatch_async(dispatch_get_main_queue(), { + () -> Void in + self.photoScrubberView.reloadData(); + }) + } + + for var bild = start; bild < end; bild++ { + let sizeHi = (Int(bytes[index++]) << 24) + (Int(bytes[index++]) << 16) + let size = (Int(bytes[index++]) << 8) + Int(bytes[index++]) + sizeHi + + if size > 0 { + // var buf = //UnsafeMutablePointer(&bytes[index]) + let part = d.subdataWithRange(NSMakeRange(index, size)) + if let img = UIImage(data: part) { + let imageRef = img.CGImage; + let bytesPerPixel = CGImageGetBitsPerPixel(imageRef) / 8; + let cost = CGImageGetWidth(imageRef) * CGImageGetHeight(imageRef) * bytesPerPixel; + self.total += d.length + + let i = self.items[bild] +// print("\(time) preload combi image loaded \(i.name) cost \(cost) total\(self.total)") + self.imageCache.setObject(img, forKey: i.thumbUrlAbsolute, cost: size) + } + } + index += size + } } func preload(start: Int, count: Int) { - let dateFormatter = NSDateFormatter() + dateFormatter.dateFormat = "HH:mm:ss.SSSZ" var preview = "" - let end = start + count + var end = start + count + if end > items.count { + end = items.count + } for var k = start; k < end; k++ { let tu = items[k].thumbUrl!.stringByReplacingOccurrencesOfString("?preview=true", withString: "") preview += "\(tu);" @@ -83,94 +146,20 @@ class MediaPhotoController: NIToolbarPhotoViewController, NIPhotoAlbumScrollView let time = dateFormatter.stringFromDate(NSDate()) print("\(time) preload image \(u2)") - let op1 = DataLoadOperation(imageURL: URL, succeeder: { - da in - if da.length > 0 { - let d = da as! NSData - - let bytes = Array(UnsafeBufferPointer(start: UnsafePointer(d.bytes), count: d.length)) - let string1 = NSString(data: d, encoding: NSUTF8StringEncoding) - print(string1) - var index = 0 - let fHi = (Int(bytes[index++]) << 24)+(Int(bytes[index++]) << 16) - let f = fHi + (Int(bytes[index++]) << 8) + Int(bytes[index++]) -// let f = (bytes[index++] << 24)+(bytes[index++] << 16)+(bytes[index++] << 8) + bytes[index++] - let time = dateFormatter.stringFromDate(NSDate()) - print("\(time) start \(start) count \(f) size \(d.length)") - - var rest = self.items.count - self.currentIndex - if rest > 40 { - rest = 40 - } - - if rest > 0 { - self.preload(self.currentIndex, count: rest) - self.currentIndex += rest + urlSession!.dataTaskWithURL(URL) { + (da, response, error) in + if let d = da { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) { + () -> Void in + self.loadData(d, start: start, end: end) } - - for var bild = start; bild < end; bild++ { - let sizeHi = (Int(bytes[index++]) << 24)+(Int(bytes[index++]) << 16) - let size = (Int(bytes[index++]) << 8) + Int(bytes[index++]) + sizeHi - - if size > 0 { - // var buf = //UnsafeMutablePointer(&bytes[index]) - let part = d.subdataWithRange(NSMakeRange(index, size)) - if let img = UIImage(data: part) { - let imageRef = img.CGImage; - let bytesPerPixel = CGImageGetBitsPerPixel(imageRef) / 8; - let cost = CGImageGetWidth(imageRef) * CGImageGetHeight(imageRef) * bytesPerPixel; - self.total += d.length - - let i = self.items[bild] -// print("\(time) preload combi image loaded \(i.name) cost \(cost) total\(self.total)") - self.imageCache.setObject(img, forKey: i.thumbUrlAbsolute, cost: size) - } - } - index += size - } - } - }, index: start) - op1.qualityOfService = NSQualityOfService.Background - backgroundOperationQueue.addOperation(op1) + }.resume() +// op1.qualityOfService = NSQualityOfService.Background +// backgroundOperationQueue.addOperation(op1) } else { print("## Invalid URL: \(u2)") } - - - -// for i in items { -// if j++ > 1000 { -// break -// } -// -// let u1 = NSURL(string: i.thumbUrlAbsolute) -// -// if let URL = u1 { -// let time = dateFormatter.stringFromDate(NSDate()) -// print("\(time) preload image \(i.name)") -// -// let op1 = DataLoadOperation(imageURL: URL, succeeder: { -// d in -// if d.length > 0 { -// if let img = UIImage(data: d) { -// let imageRef = img.CGImage; -// let bytesPerPixel = CGImageGetBitsPerPixel(imageRef) / 8; -// let cost = CGImageGetWidth(imageRef) * CGImageGetHeight(imageRef) * bytesPerPixel; -// self.total += d.length -// -// let time = dateFormatter.stringFromDate(NSDate()) -// print("\(time) preload image loaded \(i.name) cost \(cost) total\(self.total)") -// self.imageCache.setObject(img, forKey: i.thumbUrlAbsolute, cost: d.length) -// } -// } -// }, index: j) -// op1.qualityOfService = NSQualityOfService.Background -// backgroundOperationQueue.addOperation(op1) -// } else { -// print("## Invalid URL: \(i.thumbUrlAbsolute)") -// } -// } } override func didReceiveMemoryWarning() { @@ -194,6 +183,13 @@ class MediaPhotoController: NIToolbarPhotoViewController, NIPhotoAlbumScrollView } func back() { + imageCache.removeAllObjects() + operationQueue.cancelAllOperations() + + if sessionOwner { + urlSession!.invalidateAndCancel() + } + completionHandler!() } @@ -240,13 +236,13 @@ class MediaPhotoController: NIToolbarPhotoViewController, NIPhotoAlbumScrollView (request, response, result) in var im = [MediaItem]() - + if let json = result.value { for s in json as! [String] { if s.hasSuffix(".jpg") { let l = s.length - let name = NSURL(fileURLWithPath: s ).lastPathComponent! + let name = NSURL(fileURLWithPath: s).lastPathComponent! var pathlen = l - len - name.length // if (pathlen > 1000) { @@ -276,6 +272,7 @@ class MediaPhotoController: NIToolbarPhotoViewController, NIPhotoAlbumScrollView } let pc = MediaPhotoController() + pc.urlSession = self.urlSession! pc.items = im pc.completionHandler = { @@ -379,7 +376,7 @@ class MediaPhotoController: NIToolbarPhotoViewController, NIPhotoAlbumScrollView self.photoScrubberView.didLoadThumbnail(i, atIndex: photoAtIndex); } } - }, index: photoAtIndex) + }, index: photoAtIndex, session: urlSession!) op3.qualityOfService = NSQualityOfService.UserInteractive operationQueue.addOperation(op3) } @@ -445,19 +442,19 @@ class MediaPhotoController: NIToolbarPhotoViewController, NIPhotoAlbumScrollView return nil } + var image: UIImage? let newItem = items[thumbnailIndex] + let u1 = NSURL(string: newItem.thumbUrlAbsolute) - var image: UIImage? + if let URL = u1 { - image = imageCache.objectForKey(newItem.thumbUrlAbsolute) as? UIImage + image = imageCache.objectForKey(URL.absoluteString) as? UIImage - if (image == nil) { - let u1 = NSURL(string: newItem.thumbUrlAbsolute) - if let URL = u1 { - let op3 = DataLoadOperation(imageURL: URL, succeeder: { - d in + if (image == nil) { + urlSession!.dataTaskWithURL(URL) { + (da, response, error) in - if d.length > 0 { + if let d = da { if let i = UIImage(data: d) { // println("thumb image loaded \(newItem.thumbUrlAbsolute)") let imageRef = i.CGImage; @@ -469,13 +466,12 @@ class MediaPhotoController: NIToolbarPhotoViewController, NIPhotoAlbumScrollView self.photoScrubberView.didLoadThumbnail(i, atIndex: thumbnailIndex); } } - }, index: thumbnailIndex) - op3.qualityOfService = NSQualityOfService.UserInitiated - operationQueue.addOperation(op3) - } else { - print("## Invalid URL: \(newItem.thumbUrlAbsolute)") + } } } + else { + print("## Invalid URL: \(newItem.thumbUrlAbsolute)") + } return image } diff --git a/kplayer/util/DataLoadOperation.swift b/kplayer/util/DataLoadOperation.swift index 8c3008a..6c0b370 100644 --- a/kplayer/util/DataLoadOperation.swift +++ b/kplayer/util/DataLoadOperation.swift @@ -17,11 +17,14 @@ class DataLoadOperation: NSOperation { var ready1 = false + let backgroundSession: NSURLSession + var downloadTask: NSURLSessionDataTask? - init(imageURL: NSURL, succeeder: Succeeder, index: Int) { + init(imageURL: NSURL, succeeder: Succeeder, index: Int, session: NSURLSession) { self.imageURL = imageURL self.succeeder = succeeder self.index = index + self.backgroundSession = session } override func main() { @@ -31,11 +34,11 @@ class DataLoadOperation: NSOperation { let dateFormatter = NSDateFormatter() dateFormatter.dateFormat = "HH:mm:ss.SSS" - var configuration = NSURLSessionConfiguration.defaultSessionConfiguration(); // backgroundSessionConfigurationWithIdentifier("imageLoad"); - configuration.HTTPMaximumConnectionsPerHost = 100; - var backgroundSession = NSURLSession(configuration: configuration, delegate: nil, delegateQueue: nil); +// var configuration = NSURLSessionConfiguration.defaultSessionConfiguration(); // backgroundSessionConfigurationWithIdentifier("imageLoad"); +// configuration.HTTPMaximumConnectionsPerHost = 100; +// var backgroundSession = NSURLSession(configuration: configuration, delegate: nil, delegateQueue: nil); var url = NSURLRequest(URL: imageURL); - var downloadTask = backgroundSession.dataTaskWithRequest(url, completionHandler: { + downloadTask = backgroundSession.dataTaskWithRequest(url, completionHandler: { data,response,error in if error == nil { @@ -58,7 +61,7 @@ class DataLoadOperation: NSOperation { let time = dateFormatter.stringFromDate(NSDate()) // print("\(time) preload image \(imageURL)") - downloadTask.resume(); + downloadTask!.resume(); // Alamofire.request(.GET, imageURL).response { @@ -72,6 +75,10 @@ class DataLoadOperation: NSOperation { ready1 = true + if let t = downloadTask { + t.cancel() + } + super.cancel() } diff --git a/kplayer/util/ImageLoadOperation.swift b/kplayer/util/ImageLoadOperation.swift index 0ad8966..a5db54f 100644 --- a/kplayer/util/ImageLoadOperation.swift +++ b/kplayer/util/ImageLoadOperation.swift @@ -31,12 +31,17 @@ class ImageLoadOperation: NSOperation { return } + let r = NSMutableURLRequest(URL: imageURL) + r.HTTPBody = nil + r.addValue("0", forHTTPHeaderField: "Content-Length") + if let m = manager { - request = m.request(.GET, imageURL) + request = m.request(.GET, r) } else { - request = Alamofire.request(.GET, imageURL) + request = Alamofire.request(.GET, r) } + request!.validate().response { (request, response, data, error) in if let e = error as? NSError { if (e.code != -999) {