Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implement NSButton extension for OSX #287

Merged
merged 1 commit into from
Apr 21, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions Kingfisher.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

/* Begin PBXBuildFile section */
0D9C68098E20AB4F19D7C313 /* libPods-KingfisherTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A9E621E297FEFAD35D39C34E /* libPods-KingfisherTests.a */; };
185218B41CC07F6D00BD58DE /* NSButton+Kingfisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 185218B31CC07F6D00BD58DE /* NSButton+Kingfisher.swift */; };
185218B61CC07F8300BD58DE /* NSButtonExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 185218B51CC07F8300BD58DE /* NSButtonExtensionTests.swift */; };
4A54251331E840CB85C78FA8 /* libPods-KingfisherTests-OSX.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 50ECD18204CB0CD37B49F631 /* libPods-KingfisherTests-OSX.a */; };
4B164AD01B8D556900768EC6 /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B164ACE1B8D554200768EC6 /* CFNetwork.framework */; };
4B2944641C3D03980088C3E7 /* Kingfisher.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B2944481C3D01B20088C3E7 /* Kingfisher.framework */; };
Expand Down Expand Up @@ -247,6 +249,8 @@

/* Begin PBXFileReference section */
026040C607726792406566BB /* Pods-KingfisherTests-tvOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-KingfisherTests-tvOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-KingfisherTests-tvOS/Pods-KingfisherTests-tvOS.release.xcconfig"; sourceTree = "<group>"; };
185218B31CC07F6D00BD58DE /* NSButton+Kingfisher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSButton+Kingfisher.swift"; sourceTree = "<group>"; };
185218B51CC07F8300BD58DE /* NSButtonExtensionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSButtonExtensionTests.swift; sourceTree = "<group>"; };
4B164ACE1B8D554200768EC6 /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = System/Library/Frameworks/CFNetwork.framework; sourceTree = SDKROOT; };
4B2944481C3D01B20088C3E7 /* Kingfisher.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Kingfisher.framework; sourceTree = BUILT_PRODUCTS_DIR; };
4B2944551C3D03880088C3E7 /* Kingfisher-OSX-Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Kingfisher-OSX-Demo.app"; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -450,6 +454,7 @@
D10945F41C526B6C001408EB /* String+MD5.swift */,
D10945F51C526B6C001408EB /* ThreadHelper.swift */,
D10945F61C526B6C001408EB /* UIButton+Kingfisher.swift */,
185218B31CC07F6D00BD58DE /* NSButton+Kingfisher.swift */,
);
name = Sources;
sourceTree = "<group>";
Expand Down Expand Up @@ -492,6 +497,7 @@
D12E0C4C1C47F23500AC98AD /* KingfisherTestHelper.swift */,
D12E0C4D1C47F23500AC98AD /* KingfisherTests-Bridging-Header.h */,
D12E0C4E1C47F23500AC98AD /* UIButtonExtensionTests.swift */,
185218B51CC07F8300BD58DE /* NSButtonExtensionTests.swift */,
);
name = KingfisherTests;
path = Tests/KingfisherTests;
Expand Down Expand Up @@ -1261,6 +1267,7 @@
D109461D1C526C61001408EB /* ImageTransition.swift in Sources */,
D109461E1C526C61001408EB /* ImageView+Kingfisher.swift in Sources */,
D109461F1C526C61001408EB /* KingfisherManager.swift in Sources */,
185218B41CC07F6D00BD58DE /* NSButton+Kingfisher.swift in Sources */,
D10946201C526C61001408EB /* KingfisherOptionsInfo.swift in Sources */,
D10946211C526C61001408EB /* Resource.swift in Sources */,
D9638BA21C7DBA660046523D /* ImagePrefetcher.swift in Sources */,
Expand Down Expand Up @@ -1299,6 +1306,7 @@
buildActionMask = 2147483647;
files = (
D12E0C891C47F7B700AC98AD /* KingfisherTestHelper.swift in Sources */,
185218B61CC07F8300BD58DE /* NSButtonExtensionTests.swift in Sources */,
D12E0C821C47F7AF00AC98AD /* ImageCacheTests.swift in Sources */,
D12E0C831C47F7AF00AC98AD /* ImageDownloaderTests.swift in Sources */,
D9638BA81C7DCF570046523D /* ImagePrefetcherTests.swift in Sources */,
Expand Down
268 changes: 268 additions & 0 deletions NSButton+Kingfisher.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,268 @@
//
// NSButton+Kingfisher.swift
// Kingfisher
//
// Created by Jie Zhang on 14/04/2016.
//
// Copyright (c) 2016 Wei Wang <[email protected]>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.


import AppKit

// MARK: - Set Images
/**
* Set image to use from web.
*/
extension NSButton {

/**
Set an image with a URL, a placeholder image, options, progress handler and completion handler.

- parameter URL: The URL of image.
- parameter placeholderImage: A placeholder image when retrieving the image at URL.
- parameter optionsInfo: A dictionary could control some behaviors. See `KingfisherOptionsInfo` for more.
- parameter progressBlock: Called when the image downloading progress gets updated.
- parameter completionHandler: Called when the image retrieved and set.

- returns: A task represents the retrieving process.

- note: Both the `progressBlock` and `completionHandler` will be invoked in main thread.
The `CallbackDispatchQueue` specified in `optionsInfo` will not be used in callbacks of this method.
*/

public func kf_setImageWithURL(URL: NSURL,
placeholderImage: Image? = nil,
optionsInfo: KingfisherOptionsInfo? = nil,
progressBlock: DownloadProgressBlock? = nil,
completionHandler: CompletionHandler? = nil) -> RetrieveImageTask
{
return kf_setImageWithResource(Resource(downloadURL: URL),
placeholderImage: placeholderImage,
optionsInfo: optionsInfo,
progressBlock: progressBlock,
completionHandler: completionHandler)
}


/**
Set an image with a URL, a placeholder image, options, progress handler and completion handler.

- parameter resource: Resource object contains information such as `cacheKey` and `downloadURL`.
- parameter placeholderImage: A placeholder image when retrieving the image at URL.
- parameter optionsInfo: A dictionary could control some behaviors. See `KingfisherOptionsInfo` for more.
- parameter progressBlock: Called when the image downloading progress gets updated.
- parameter completionHandler: Called when the image retrieved and set.

- returns: A task represents the retrieving process.

- note: Both the `progressBlock` and `completionHandler` will be invoked in main thread.
The `CallbackDispatchQueue` specified in `optionsInfo` will not be used in callbacks of this method.
*/
public func kf_setImageWithResource(resource: Resource,
placeholderImage: Image? = nil,
optionsInfo: KingfisherOptionsInfo? = nil,
progressBlock: DownloadProgressBlock? = nil,
completionHandler: CompletionHandler? = nil) -> RetrieveImageTask
{
image = placeholderImage
kf_setWebURL(resource.downloadURL)
let task = KingfisherManager.sharedManager.retrieveImageWithResource(resource, optionsInfo: optionsInfo,
progressBlock: { receivedSize, totalSize in
if let progressBlock = progressBlock {
progressBlock(receivedSize: receivedSize, totalSize: totalSize)
}
},
completionHandler: {[weak self] image, error, cacheType, imageURL in
dispatch_async_safely_to_main_queue {
guard let sSelf = self where imageURL == sSelf.kf_webURL else {
completionHandler?(image: image, error: error, cacheType: cacheType, imageURL: imageURL)
return
}

sSelf.kf_setImageTask(nil)

guard let image = image else {
completionHandler?(image: nil, error: error, cacheType: cacheType, imageURL: imageURL)
return
}

sSelf.image = image
completionHandler?(image: image, error: error, cacheType: cacheType, imageURL: imageURL)
}
})

kf_setImageTask(task)
return task
}

}


// MARK: - Associated Object
private var lastURLKey: Void?
private var imageTaskKey: Void?

extension NSButton {
/// Get the image URL binded to this image view.
public var kf_webURL: NSURL? {
return objc_getAssociatedObject(self, &lastURLKey) as? NSURL
}

private func kf_setWebURL(URL: NSURL) {
objc_setAssociatedObject(self, &lastURLKey, URL, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}

private var kf_imageTask: RetrieveImageTask? {
return objc_getAssociatedObject(self, &imageTaskKey) as? RetrieveImageTask
}

private func kf_setImageTask(task: RetrieveImageTask?) {
objc_setAssociatedObject(self, &imageTaskKey, task, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}

/**
* Set alternate image to use from web.
*/
extension NSButton {

/**
Set an alternateImage with a URL, a placeholder image, options, progress handler and completion handler.

- parameter URL: The URL of image.
- parameter placeholderImage: A placeholder image when retrieving the image at URL.
- parameter optionsInfo: A dictionary could control some behaviors. See `KingfisherOptionsInfo` for more.
- parameter progressBlock: Called when the image downloading progress gets updated.
- parameter completionHandler: Called when the image retrieved and set.

- returns: A task represents the retrieving process.

- note: Both the `progressBlock` and `completionHandler` will be invoked in main thread.
The `CallbackDispatchQueue` specified in `optionsInfo` will not be used in callbacks of this method.
*/

public func kf_setAlternateImageWithURL(URL: NSURL,
placeholderImage: Image? = nil,
optionsInfo: KingfisherOptionsInfo? = nil,
progressBlock: DownloadProgressBlock? = nil,
completionHandler: CompletionHandler? = nil) -> RetrieveImageTask
{
return kf_setAlternateImageWithResource(Resource(downloadURL: URL),
placeholderImage: placeholderImage,
optionsInfo: optionsInfo,
progressBlock: progressBlock,
completionHandler: completionHandler)
}


/**
Set an alternateImage with a URL, a placeholder image, options, progress handler and completion handler.

- parameter resource: Resource object contains information such as `cacheKey` and `downloadURL`.
- parameter placeholderImage: A placeholder image when retrieving the image at URL.
- parameter optionsInfo: A dictionary could control some behaviors. See `KingfisherOptionsInfo` for more.
- parameter progressBlock: Called when the image downloading progress gets updated.
- parameter completionHandler: Called when the image retrieved and set.

- returns: A task represents the retrieving process.

- note: Both the `progressBlock` and `completionHandler` will be invoked in main thread.
The `CallbackDispatchQueue` specified in `optionsInfo` will not be used in callbacks of this method.
*/
public func kf_setAlternateImageWithResource(resource: Resource,
placeholderImage: Image? = nil,
optionsInfo: KingfisherOptionsInfo? = nil,
progressBlock: DownloadProgressBlock? = nil,
completionHandler: CompletionHandler? = nil) -> RetrieveImageTask
{
alternateImage = placeholderImage
kf_setAlternateWebURL(resource.downloadURL)
let task = KingfisherManager.sharedManager.retrieveImageWithResource(resource, optionsInfo: optionsInfo,
progressBlock: { receivedSize, totalSize in
if let progressBlock = progressBlock {
progressBlock(receivedSize: receivedSize, totalSize: totalSize)
}
},
completionHandler: {[weak self] image, error, cacheType, imageURL in
dispatch_async_safely_to_main_queue {
guard let sSelf = self where imageURL == sSelf.kf_alternateWebURL else {
completionHandler?(image: image, error: error, cacheType: cacheType, imageURL: imageURL)
return
}

sSelf.kf_setAlternateImageTask(nil)

guard let image = image else {
completionHandler?(image: nil, error: error, cacheType: cacheType, imageURL: imageURL)
return
}

sSelf.alternateImage = image
completionHandler?(image: image, error: error, cacheType: cacheType, imageURL: imageURL)
}
})

kf_setImageTask(task)
return task
}
}

private var lastAlternateURLKey: Void?
private var alternateImageTaskKey: Void?

// MARK: - Runtime for NSButton alternateImage
extension NSButton {
/**
Get the alternate image URL binded to this button.
*/

public var kf_alternateWebURL: NSURL? {
return objc_getAssociatedObject(self, &lastAlternateURLKey) as? NSURL
}

private func kf_setAlternateWebURL(URL: NSURL) {
objc_setAssociatedObject(self, &lastAlternateURLKey, URL, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}

private var kf_alternateImageTask: RetrieveImageTask? {
return objc_getAssociatedObject(self, &alternateImageTaskKey) as? RetrieveImageTask
}

private func kf_setAlternateImageTask(task: RetrieveImageTask?) {
objc_setAssociatedObject(self, &alternateImageTaskKey, task, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}


// MARK: - Cancel image download tasks.
extension NSButton {
/**
Cancel the image download task bounded to the image view if it is running.
Nothing will happen if the downloading has already finished.
*/
public func kf_cancelImageDownloadTask() {
kf_imageTask?.downloadTask?.cancel()
}

public func kf_cancelAlternateImageDownloadTask() {
kf_imageTask?.downloadTask?.cancel()
}
}
Loading