diff --git a/kplayer.xcodeproj/project.pbxproj b/kplayer.xcodeproj/project.pbxproj index 645415d..16a1b4f 100644 --- a/kplayer.xcodeproj/project.pbxproj +++ b/kplayer.xcodeproj/project.pbxproj @@ -22,6 +22,7 @@ 1C73654C9EA6D255CFC039C5 /* NetworkHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C73620D01687FB4F1811C5C /* NetworkHelper.swift */; }; 1C7365885FAF292F2221ED44 /* MediaPhotoController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C73673DC671535E3A049F54 /* MediaPhotoController.swift */; }; 1C73677CD719D0F82D144BF6 /* Bool.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736C43137E3B8391E5F07B /* Bool.swift */; }; + 1C7367AF39961D2BA72480ED /* DataLoadOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736F9338CE36708244D42A /* DataLoadOperation.swift */; }; 1C7368364397315E12E90F05 /* VideoPlayerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7367379DEE94EBF3FAFA78 /* VideoPlayerController.swift */; }; 1C73688D13E5A804880C8768 /* UIImageExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736DCCE3AA9993E15F7652 /* UIImageExtension.swift */; }; 1C73689C7E6A25E758B16C54 /* String.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C73653A9EBCC466FD4E3DA6 /* String.swift */; }; @@ -93,6 +94,7 @@ 1C736DB8164E3EF18FA6F28D /* NSArray.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSArray.swift; sourceTree = ""; }; 1C736DCCE3AA9993E15F7652 /* UIImageExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIImageExtension.swift; sourceTree = ""; }; 1C736E7B8BAD989DC544088E /* Range.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Range.swift; sourceTree = ""; }; + 1C736F9338CE36708244D42A /* DataLoadOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataLoadOperation.swift; sourceTree = ""; }; 5C6CBA548F885BF342F594EA /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = ""; }; A170BFB886D61D57F7009BFC /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = ""; }; C98AF5CF1B124D6A00D196CC /* kplayer.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = kplayer.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -187,6 +189,7 @@ 1C7360744ABACC3557D05760 /* HanekeFetchOperation.swift */, 1C7360A94DBECA685ED8602F /* ImageLoadOperation.swift */, 1C736C60C423AE87B8D0F22A /* alamoimage.swift */, + 1C736F9338CE36708244D42A /* DataLoadOperation.swift */, ); path = util; sourceTree = ""; @@ -467,6 +470,7 @@ 1C736D16E81BA1FB325200E0 /* HanekeFetchOperation.swift in Sources */, 1C736D24891597F2728230EE /* ImageLoadOperation.swift in Sources */, 1C73626E34BA4D64ACF94AE5 /* alamoimage.swift in Sources */, + 1C7367AF39961D2BA72480ED /* DataLoadOperation.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/kplayer/detail/ItemCell.swift b/kplayer/detail/ItemCell.swift index 5f6ec05..a0ca3a7 100644 --- a/kplayer/detail/ItemCell.swift +++ b/kplayer/detail/ItemCell.swift @@ -41,7 +41,7 @@ class ItemCell: UICollectionViewCell { } else { if let i = item.image { image.image = i.scaleToSize(15 * 16, height: 15 * 9) - image.sizeToFit() +// image.sizeToFit() } else { image.image = defaultImage } diff --git a/kplayer/photo/MediaPhotoController.swift b/kplayer/photo/MediaPhotoController.swift index 5003cfd..c5cf948 100644 --- a/kplayer/photo/MediaPhotoController.swift +++ b/kplayer/photo/MediaPhotoController.swift @@ -15,61 +15,87 @@ class MediaPhotoController: NIToolbarPhotoViewController, NIPhotoAlbumScrollView var requests = Array() - let THUMBS = "thumb" + var imageCache = NSCache() + var total = 0 - var imageCache = Cache(name: "thumbnails") + lazy var backgroundOperationQueue: NSOperationQueue = { + var queue = NSOperationQueue() + queue.name = "Thumb queue" + queue.maxConcurrentOperationCount = 1 + return queue + }() lazy var operationQueue: NSOperationQueue = { var queue = NSOperationQueue() queue.name = "Photo queue" - queue.maxConcurrentOperationCount = 5 + queue.maxConcurrentOperationCount = 6 return queue }() - override func viewDidLoad() { - let thumbFormat = Format(name: THUMBS, diskCapacity: 100 * 1024 * 1024) - imageCache.addFormat(thumbFormat) + override func viewDidDisappear(animated: Bool) { + backgroundOperationQueue.cancelAllOperations() + } + override func viewDidLoad() { super.viewDidLoad() + imageCache.totalCostLimit = 1024 * 1024 * 50 + let backButton = UIBarButtonItem(barButtonSystemItem: .Cancel, target: self, action: Selector("back")) navigationItem.leftBarButtonItems = [backButton] let playButton = UIBarButtonItem(barButtonSystemItem: .Play, target: self, action: Selector("play")) - navigationItem.rightBarButtonItems = [playButton] + let shotButton = UIBarButtonItem(barButtonSystemItem: .Camera, target: self, action: Selector("shot")) + navigationItem.rightBarButtonItems = [playButton, shotButton] setChromeVisibility(true, animated: true) self.photoAlbumView.reloadData(); self.photoScrubberView.reloadData(); - let back = NSURLSessionConfiguration.ephemeralSessionConfiguration() - - let bsession = NSURLSession(configuration: back) - - var j=0; + var j = 0; for i in items { if j++ > 1000 { break } + let URL = NSURL(string: i.thumbUrlAbsolute)! - let fetcher = MediaFetcher(URL: URL, session: bsession) - let fetch = imageCache.fetch(fetcher: fetcher, formatName: THUMBS, failure: nil, success: nil) - fetch.onSuccess { - s in - println ("preload \(s)") - } + let op1 = ImageLoadOperation(imageURL: URL, succeeder: { + img in + let imageRef = img.CGImage; + let bytesPerPixel = CGImageGetBitsPerPixel(imageRef) / 8; + let cost = CGImageGetWidth(imageRef) * CGImageGetHeight(imageRef) * bytesPerPixel; + self.total += cost + println("preload image loaded \(i.thumbUrlAbsolute) cost \(cost) total\(self.total)") + self.imageCache.setObject(img, forKey: i.thumbUrlAbsolute, cost: cost) + }, index: j) + op1.qualityOfService = NSQualityOfService.Background + backgroundOperationQueue.addOperation(op1) } } override func didReceiveMemoryWarning() { println("warning") + imageCache.removeAllObjects() + super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } + func shot() { + let currentItem = items[photoAlbumView.centerPageIndex] + var imageUrl = currentItem.thumbUrl!.stringByReplacingOccurrencesOfString("_thumb.jpg", withString: ".jpg") + imageUrl = imageUrl.stringByReplacingOccurrencesOfString("?preview=true", withString: "") + let url = NetworkManager.sharedInstance.baseurl + "/service/linkfavpic" + imageUrl + + println(url) + Alamofire.request(.GET, url).responseString { + (_, _, string, _) in + println("ok") + } + } func back() { completionHandler!() @@ -185,7 +211,7 @@ class MediaPhotoController: NIToolbarPhotoViewController, NIPhotoAlbumScrollView func photoAlbumScrollView(photoAlbumScrollView: NIPhotoAlbumScrollView!, photoAtIndex: Int, photoSize: UnsafeMutablePointer, isLoading: UnsafeMutablePointer, originalPhotoDimensions: UnsafeMutablePointer) -> UIImage! { let c = count(items) - // println("Index: \(photoAtIndex) of \(c)") + // println("Index: \(photoAtIndex) of \(c)") let newItem = items[photoAtIndex] let hqURL = NSURL(string: newItem.imageUrlAbsolute)! let URL = NSURL(string: newItem.thumbUrlAbsolute)! @@ -194,27 +220,6 @@ class MediaPhotoController: NIToolbarPhotoViewController, NIPhotoAlbumScrollView var size = NIPhotoScrollViewPhotoSizeUnknown - imageCache.fetch(key: URL.absoluteString!, formatName: THUMBS).onSuccess { - i in - image = i - size = NIPhotoScrollViewPhotoSizeThumbnail - self.photoAlbumView.didLoadPhoto(image, atIndex: photoAtIndex, photoSize: size) - } - - if let i = image { - isLoading[0] = false - } else { - let fetcher = NetworkFetcher(URL: URL) - let fetch = imageCache.fetch(fetcher: fetcher, formatName: THUMBS, failure: nil, success: nil) - - fetch.onSuccess { - i in - println("thumb loaded \(newItem.imageUrlAbsolute)") - size = NIPhotoScrollViewPhotoSizeThumbnail - self.photoAlbumView.didLoadPhoto(image, atIndex: photoAtIndex, photoSize: size) - } - } - for r in requests { let pages = self.photoAlbumView.visiblePages() as NSMutableSet! var ok = false @@ -231,14 +236,39 @@ class MediaPhotoController: NIToolbarPhotoViewController, NIPhotoAlbumScrollView } } + image = imageCache.objectForKey(URL.absoluteString!) as? UIImage + + if let i = image { + size = NIPhotoScrollViewPhotoSizeThumbnail + isLoading[0] = false + } else { + let URL = NSURL(string: newItem.thumbUrlAbsolute)! + + let op3 = ImageLoadOperation(imageURL: URL, succeeder: { + i in +// println("thumb preload image loaded \(newItem.imageUrlAbsolute)") + let imageRef = i.CGImage; + let bytesPerPixel = CGImageGetBitsPerPixel(imageRef) / 8; + let cost = CGImageGetWidth(imageRef) * CGImageGetHeight(imageRef) * bytesPerPixel; + self.imageCache.setObject(i, forKey: newItem.thumbUrlAbsolute, cost: cost) + size = NIPhotoScrollViewPhotoSizeThumbnail + self.photoAlbumView.didLoadPhoto(i, atIndex: photoAtIndex, photoSize: size) + self.photoScrubberView.didLoadThumbnail(i, atIndex: photoAtIndex); + }, index: photoAtIndex) + op3.qualityOfService = NSQualityOfService.UserInteractive + requests.append(op3) + operationQueue.addOperation(op3) + } + let op2 = ImageLoadOperation(imageURL: hqURL, succeeder: { i in - println("image loaded \(newItem.imageUrlAbsolute) at \(photoAtIndex)") +// println("image loaded \(newItem.imageUrlAbsolute) at \(photoAtIndex)") size = NIPhotoScrollViewPhotoSizeOriginal self.photoAlbumView.didLoadPhoto(i, atIndex: photoAtIndex, photoSize: size) photoSize[0] = size }, index: photoAtIndex) + op2.qualityOfService = NSQualityOfService.UserInitiated requests.append(op2) operationQueue.addOperation(op2) @@ -288,28 +318,41 @@ class MediaPhotoController: NIToolbarPhotoViewController, NIPhotoAlbumScrollView let c = count(items) let newItem = items[thumbnailIndex] - let URL = NSURL(string: newItem.thumbUrlAbsolute)! - let fetcher = NetworkFetcher(URL: URL) - let fetch = imageCache.fetch(fetcher: fetcher, formatName: THUMBS, failure: nil, success: nil) + var image: UIImage? - fetch.onSuccess { - i in + image = imageCache.objectForKey(newItem.thumbUrlAbsolute) as? UIImage - self.photoScrubberView.didLoadThumbnail(i, atIndex: thumbnailIndex); + if (image == nil) { + let URL = NSURL(string: newItem.thumbUrlAbsolute)! + let op3 = ImageLoadOperation(imageURL: URL, succeeder: { + i in +// println("thumb image loaded \(newItem.thumbUrlAbsolute)") + let imageRef = i.CGImage; + let bytesPerPixel = CGImageGetBitsPerPixel(imageRef) / 8; + let cost = CGImageGetWidth(imageRef) * CGImageGetHeight(imageRef) * bytesPerPixel; + + self.imageCache.setObject(i, forKey: newItem.thumbUrlAbsolute, cost: cost) + + self.photoScrubberView.didLoadThumbnail(i, atIndex: thumbnailIndex); + }, index: thumbnailIndex) + op3.qualityOfService = NSQualityOfService.UserInitiated + operationQueue.addOperation(op3) } - return nil + return image } } -class MediaFetcher : NetworkFetcher { +class MediaFetcher: NetworkFetcher { let bsession: NSURLSession? - init(URL : NSURL, session: NSURLSession) { + init(URL: NSURL, session: NSURLSession) { self.bsession = session super.init(URL: URL) } - override public var session : NSURLSession { return bsession! } + override public var session: NSURLSession { + return bsession! + } } diff --git a/kplayer/util/DataLoadOperation.swift b/kplayer/util/DataLoadOperation.swift new file mode 100644 index 0000000..28f24ed --- /dev/null +++ b/kplayer/util/DataLoadOperation.swift @@ -0,0 +1,62 @@ +// +// Created by Marco Schmickler on 21.03.15. +// Copyright (c) 2015 Marco Schmickler. All rights reserved. +// + +import Foundation +import Alamofire +import Darwin + +class ImageLoadOperation: NSOperation { + public typealias Succeeder = (NSData) -> () + + let imageURL: NSURL + let succeeder: Succeeder + let index: Int + var request: Request? + + var manager: Manager? + + var ready1 = false + + + init(imageURL: NSURL, succeeder: Succeeder, index: Int) { + self.imageURL = imageURL + self.succeeder = succeeder + self.index = index + } + + override func main() { + if self.cancelled { + return + } + + // println("do load \(imageURL.absoluteString!)") + + if let m = manager { + request = m.request(.GET, imageURL) + } else { + request = Alamofire.request(.GET, imageURL) + } + + request!.validate().response { (request, response, data, error) in + self.succeeder(data) + } + + while !ready1 { + usleep(10000) + } + } + + override func cancel() { +// println("cancel load \(imageURL.absoluteString!)") + + ready1 = true + if let r = request { + r.cancel() + } + + super.cancel() + } + +} diff --git a/kplayer/util/ImageLoadOperation.swift b/kplayer/util/ImageLoadOperation.swift index 335c780..a6333b8 100644 --- a/kplayer/util/ImageLoadOperation.swift +++ b/kplayer/util/ImageLoadOperation.swift @@ -13,6 +13,11 @@ class ImageLoadOperation: NSOperation { let imageURL: NSURL let succeeder: Succeeder let index: Int + var request: Request? + + var manager: Manager? + + var ready1 = false init(imageURL: NSURL, succeeder: Succeeder, index: Int) { @@ -26,21 +31,42 @@ class ImageLoadOperation: NSOperation { return } - usleep(100000) + // println("do load \(imageURL.absoluteString!)") - if self.cancelled { - return + if let m = manager { + request = m.request(.GET, imageURL) + } else { + request = Alamofire.request(.GET, imageURL) } - Alamofire.request(.GET, imageURL).validate().responseImage() { + request!.validate().responseImage() { (request, _, image, error) in if error == nil { -// if request.URLString.isEqual(self.imageURL) { + self.ready1 = true + // if request.URLString.isEqual(self.imageURL) { +// dispatch_async(dispatch_get_main_queue()) { self.succeeder(image!) - // } + // } + + // } } } + + while !ready1 { + usleep(10000) + } + } + + override func cancel() { +// println("cancel load \(imageURL.absoluteString!)") + + ready1 = true + if let r = request { + r.cancel() + } + + super.cancel() } }