mirror of
https://github.com/kiwix/kiwix-apple.git
synced 2025-09-24 04:03:03 -04:00
Operation lib refactor
This commit is contained in:
parent
c5f1f57728
commit
4ea03c6599
@ -10,7 +10,7 @@ import CoreData
|
||||
import Operations
|
||||
|
||||
@UIApplicationMain
|
||||
class AppDelegate: UIResponder, UIApplicationDelegate, OperationQueueDelegate {
|
||||
class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
|
||||
var window: UIWindow?
|
||||
var mainController: MainController? {
|
||||
|
@ -49,7 +49,7 @@
|
||||
</dict>
|
||||
</array>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.7.697</string>
|
||||
<string>1.7.699</string>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false/>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
|
@ -106,7 +106,7 @@ class Network: NSObject, NSURLSessionDelegate, NSURLSessionDownloadDelegate, NSU
|
||||
|
||||
// MARK: - OperationQueueDelegate
|
||||
|
||||
func operationQueue(operationQueue: OperationQueue, willAddOperation operation: NSOperation) {
|
||||
func operationQueue(queue: OperationQueue, willAddOperation operation: NSOperation) {
|
||||
guard operationQueue.operationCount == 0 else {return}
|
||||
shouldReportProgress = true
|
||||
NSOperationQueue.mainQueue().addOperationWithBlock { () -> Void in
|
||||
@ -114,7 +114,9 @@ class Network: NSObject, NSURLSessionDelegate, NSURLSessionDownloadDelegate, NSU
|
||||
}
|
||||
}
|
||||
|
||||
func operationQueue(operationQueue: OperationQueue, operationDidFinish operation: NSOperation, withErrors errors: [NSError]) {
|
||||
func operationQueue(queue: OperationQueue, willFinishOperation operation: NSOperation, withErrors errors: [ErrorType]) {}
|
||||
|
||||
func operationQueue(queue: OperationQueue, didFinishOperation operation: NSOperation, withErrors errors: [ErrorType]) {
|
||||
guard operationQueue.operationCount == 1 else {return}
|
||||
NSOperationQueue.mainQueue().addOperationWithBlock { () -> Void in
|
||||
self.timer?.invalidate()
|
||||
@ -122,6 +124,8 @@ class Network: NSObject, NSURLSessionDelegate, NSURLSessionDownloadDelegate, NSU
|
||||
}
|
||||
}
|
||||
|
||||
func operationQueue(queue: OperationQueue, willProduceOperation operation: NSOperation) {}
|
||||
|
||||
// MARK: - NSURLSessionDelegate
|
||||
|
||||
func URLSessionDidFinishEventsForBackgroundURLSession(session: NSURLSession) {
|
||||
|
@ -21,7 +21,7 @@
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.7.747</string>
|
||||
<string>1.7.768</string>
|
||||
<key>NSExtension</key>
|
||||
<dict>
|
||||
<key>NSExtensionMainStoryboard</key>
|
||||
|
@ -10,7 +10,6 @@
|
||||
7356F9FACBB84380CFC8F68F /* Pods_Kiwix_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EC884ACBBA260AF741C4C4FE /* Pods_Kiwix_iOS.framework */; };
|
||||
970C3DCA1CBD79450026A240 /* MigrationPolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 970C3DC91CBD79450026A240 /* MigrationPolicy.swift */; };
|
||||
970C61971D34243600087758 /* URLSessionDownloadTaskOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 970C61961D34243600087758 /* URLSessionDownloadTaskOperation.swift */; };
|
||||
970C61991D3429E400087758 /* ReachabilityCondition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 970C61981D3429E400087758 /* ReachabilityCondition.swift */; };
|
||||
970C65501D398D5A007032F8 /* BookmarkControllerAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 970C654F1D398D5A007032F8 /* BookmarkControllerAnimator.swift */; };
|
||||
970E68B21D37E1DD001E8514 /* SettingSearchTuneController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 970E68B11D37E1DD001E8514 /* SettingSearchTuneController.swift */; };
|
||||
970E68B61D37E224001E8514 /* SettingSearchHistoryTBVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 970E68B51D37E224001E8514 /* SettingSearchHistoryTBVC.swift */; };
|
||||
@ -273,7 +272,6 @@
|
||||
6DCB0E958A1083CA248C5A12 /* Pods-Kiwix-OSX.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Kiwix-OSX.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Kiwix-OSX/Pods-Kiwix-OSX.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
970C3DC91CBD79450026A240 /* MigrationPolicy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MigrationPolicy.swift; path = CoreData/Migration/MigrationPolicy.swift; sourceTree = "<group>"; };
|
||||
970C61961D34243600087758 /* URLSessionDownloadTaskOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = URLSessionDownloadTaskOperation.swift; path = Operations/URLSessionDownloadTaskOperation.swift; sourceTree = "<group>"; };
|
||||
970C61981D3429E400087758 /* ReachabilityCondition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReachabilityCondition.swift; sourceTree = "<group>"; };
|
||||
970C654F1D398D5A007032F8 /* BookmarkControllerAnimator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BookmarkControllerAnimator.swift; path = "Kiwix-iOS/Controller/Bookmark/BookmarkControllerAnimator.swift"; sourceTree = SOURCE_ROOT; };
|
||||
970E68B11D37E1DD001E8514 /* SettingSearchTuneController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SettingSearchTuneController.swift; path = "Kiwix-iOS/Controller/Setting/SettingSearchTuneController.swift"; sourceTree = SOURCE_ROOT; };
|
||||
970E68B51D37E224001E8514 /* SettingSearchHistoryTBVC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SettingSearchHistoryTBVC.swift; path = "Kiwix-iOS/Controller/Setting/SettingSearchHistoryTBVC.swift"; sourceTree = SOURCE_ROOT; };
|
||||
@ -412,9 +410,7 @@
|
||||
977998711C1E0B7900B1DD5E /* Article+CoreDataProperties.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "Article+CoreDataProperties.swift"; path = "Kiwix/CoreData/Article+CoreDataProperties.swift"; sourceTree = "<group>"; };
|
||||
977998721C1E0B7900B1DD5E /* Language+CoreDataProperties.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "Language+CoreDataProperties.swift"; path = "Kiwix/CoreData/Language+CoreDataProperties.swift"; sourceTree = "<group>"; };
|
||||
9779987A1C1E1C9600B1DD5E /* Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Extensions.swift; path = Kiwix/Extensions.swift; sourceTree = "<group>"; };
|
||||
9779A1C21D34225E0071EFAB /* AlertOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AlertOperation.swift; path = Operations/AlertOperation.swift; sourceTree = "<group>"; };
|
||||
9779A1C31D34225E0071EFAB /* GlobalOperationQueue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GlobalOperationQueue.swift; path = Operations/GlobalOperationQueue.swift; sourceTree = "<group>"; };
|
||||
9779A1C41D34225E0071EFAB /* NetworkObserver.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = NetworkObserver.swift; path = Operations/NetworkObserver.swift; sourceTree = "<group>"; };
|
||||
9779A1C51D34225E0071EFAB /* RefreshLibraryOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RefreshLibraryOperation.swift; path = Operations/RefreshLibraryOperation.swift; sourceTree = "<group>"; };
|
||||
9779A1C61D34225E0071EFAB /* SearchOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SearchOperation.swift; path = Operations/SearchOperation.swift; sourceTree = "<group>"; };
|
||||
9779A1C71D34225E0071EFAB /* UIOperations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = UIOperations.swift; path = Operations/UIOperations.swift; sourceTree = "<group>"; };
|
||||
@ -793,17 +789,6 @@
|
||||
name = Shared;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
973DD4031D343F09009D45DB /* Basic */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9779A1C21D34225E0071EFAB /* AlertOperation.swift */,
|
||||
9779A1C41D34225E0071EFAB /* NetworkObserver.swift */,
|
||||
970C61981D3429E400087758 /* ReachabilityCondition.swift */,
|
||||
9779A1C71D34225E0071EFAB /* UIOperations.swift */,
|
||||
);
|
||||
name = Basic;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
973DD4261D36E395009D45DB /* Tools */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -1106,11 +1091,11 @@
|
||||
97E5712A1CA0525300FF4F1D /* Operation */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
973DD4031D343F09009D45DB /* Basic */,
|
||||
9779A1C31D34225E0071EFAB /* GlobalOperationQueue.swift */,
|
||||
9779A1C51D34225E0071EFAB /* RefreshLibraryOperation.swift */,
|
||||
973DD4241D344558009D45DB /* ScanLocalBookOperation.swift */,
|
||||
9779A1C61D34225E0071EFAB /* SearchOperation.swift */,
|
||||
9779A1C71D34225E0071EFAB /* UIOperations.swift */,
|
||||
971C4F0D1D400F010027B7D2 /* UpdateWidgetDataSourceOperation.swift */,
|
||||
970C61961D34243600087758 /* URLSessionDownloadTaskOperation.swift */,
|
||||
);
|
||||
@ -1721,7 +1706,6 @@
|
||||
970E68BB1D3809A3001E8514 /* MainControllerDelegates.swift in Sources */,
|
||||
973DD4211D34434C009D45DB /* SearchResult.swift in Sources */,
|
||||
9779A1C91D34225E0071EFAB /* GlobalOperationQueue.swift in Sources */,
|
||||
970C61991D3429E400087758 /* ReachabilityCondition.swift in Sources */,
|
||||
978C589C1C1CD86E0077AE47 /* Article.swift in Sources */,
|
||||
973DD41E1D34428F009D45DB /* ZimMultiReader.swift in Sources */,
|
||||
);
|
||||
|
@ -1,83 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2015 Apple Inc. All Rights Reserved.
|
||||
See LICENSE.txt for this sample’s licensing information
|
||||
|
||||
Abstract:
|
||||
This file shows how to present an alert as part of an operation.
|
||||
*/
|
||||
|
||||
import UIKit
|
||||
import PSOperations
|
||||
|
||||
class AlertOperation: Operation {
|
||||
// MARK: Properties
|
||||
|
||||
private let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .Alert)
|
||||
private let presentationContext: UIViewController?
|
||||
|
||||
var title: String? {
|
||||
get {
|
||||
return alertController.title
|
||||
}
|
||||
|
||||
set {
|
||||
alertController.title = newValue
|
||||
name = newValue
|
||||
}
|
||||
}
|
||||
|
||||
var message: String? {
|
||||
get {
|
||||
return alertController.message
|
||||
}
|
||||
|
||||
set {
|
||||
alertController.message = newValue
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Initialization
|
||||
|
||||
init(presentationContext: UIViewController? = nil) {
|
||||
self.presentationContext = presentationContext ?? UIApplication.sharedApplication().keyWindow?.rootViewController
|
||||
|
||||
super.init()
|
||||
|
||||
addCondition(AlertPresentation())
|
||||
|
||||
/*
|
||||
This operation modifies the view controller hierarchy.
|
||||
Doing this while other such operations are executing can lead to
|
||||
inconsistencies in UIKit. So, let's make them mutally exclusive.
|
||||
*/
|
||||
addCondition(MutuallyExclusive<UIViewController>())
|
||||
}
|
||||
|
||||
func addAction(title: String, style: UIAlertActionStyle = .Default, handler: AlertOperation -> Void = { _ in }) {
|
||||
let action = UIAlertAction(title: title, style: style) { [weak self] _ in
|
||||
if let strongSelf = self {
|
||||
handler(strongSelf)
|
||||
}
|
||||
|
||||
self?.finish()
|
||||
}
|
||||
|
||||
alertController.addAction(action)
|
||||
}
|
||||
|
||||
override func execute() {
|
||||
guard let presentationContext = presentationContext else {
|
||||
finish()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
dispatch_async(dispatch_get_main_queue()) {
|
||||
if self.alertController.actions.isEmpty {
|
||||
self.addAction("OK")
|
||||
}
|
||||
|
||||
presentationContext.presentViewController(self.alertController, animated: true, completion: nil)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,120 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2015 Apple Inc. All Rights Reserved.
|
||||
See LICENSE.txt for this sample’s licensing information
|
||||
|
||||
Abstract:
|
||||
Contains the code to manage the visibility of the network activity indicator
|
||||
*/
|
||||
|
||||
import UIKit
|
||||
import PSOperations
|
||||
|
||||
/**
|
||||
An `OperationObserver` that will cause the network activity indicator to appear
|
||||
as long as the `Operation` to which it is attached is executing.
|
||||
*/
|
||||
struct NetworkObserver: OperationObserver {
|
||||
// MARK: Initilization
|
||||
|
||||
init() { }
|
||||
|
||||
func operationDidStart(operation: Operation) {
|
||||
print("NetworkObserver: \(operation.name ?? "Unknown") operation did start")
|
||||
dispatch_async(dispatch_get_main_queue()) {
|
||||
// Increment the network indicator's "reference count"
|
||||
NetworkIndicatorController.sharedIndicatorController.networkActivityDidStart()
|
||||
}
|
||||
}
|
||||
|
||||
func operation(operation: Operation, didProduceOperation newOperation: NSOperation) { }
|
||||
|
||||
func operationDidFinish(operation: Operation, errors: [NSError]) {
|
||||
print("NetworkObserver: \(operation.name ?? "Unknown") operation did finish")
|
||||
dispatch_async(dispatch_get_main_queue()) {
|
||||
// Decrement the network indicator's "reference count".
|
||||
NetworkIndicatorController.sharedIndicatorController.networkActivityDidEnd()
|
||||
}
|
||||
}
|
||||
|
||||
func operationDidCancel(operation: Operation) { }
|
||||
}
|
||||
|
||||
/// A singleton to manage a visual "reference count" on the network activity indicator.
|
||||
private class NetworkIndicatorController {
|
||||
// MARK: Properties
|
||||
|
||||
static let sharedIndicatorController = NetworkIndicatorController()
|
||||
|
||||
private var activityCount = 0
|
||||
|
||||
private var visibilityTimer: Timer?
|
||||
|
||||
// MARK: Methods
|
||||
|
||||
func networkActivityDidStart() {
|
||||
assert(NSThread.isMainThread(), "Altering network activity indicator state can only be done on the main thread.")
|
||||
|
||||
activityCount += 1
|
||||
|
||||
updateIndicatorVisibility()
|
||||
}
|
||||
|
||||
func networkActivityDidEnd() {
|
||||
assert(NSThread.isMainThread(), "Altering network activity indicator state can only be done on the main thread.")
|
||||
|
||||
activityCount -= 1
|
||||
|
||||
updateIndicatorVisibility()
|
||||
}
|
||||
|
||||
private func updateIndicatorVisibility() {
|
||||
if activityCount > 0 {
|
||||
showIndicator()
|
||||
}
|
||||
else {
|
||||
/*
|
||||
To prevent the indicator from flickering on and off, we delay the
|
||||
hiding of the indicator by one second. This provides the chance
|
||||
to come in and invalidate the timer before it fires.
|
||||
*/
|
||||
visibilityTimer = Timer(interval: 1.0) {
|
||||
self.hideIndicator()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func showIndicator() {
|
||||
visibilityTimer?.cancel()
|
||||
visibilityTimer = nil
|
||||
UIApplication.sharedApplication().networkActivityIndicatorVisible = true
|
||||
}
|
||||
|
||||
private func hideIndicator() {
|
||||
visibilityTimer?.cancel()
|
||||
visibilityTimer = nil
|
||||
UIApplication.sharedApplication().networkActivityIndicatorVisible = false
|
||||
}
|
||||
}
|
||||
|
||||
/// Essentially a cancellable `dispatch_after`.
|
||||
class Timer {
|
||||
// MARK: Properties
|
||||
|
||||
private var isCancelled = false
|
||||
|
||||
// MARK: Initialization
|
||||
|
||||
init(interval: NSTimeInterval, handler: dispatch_block_t) {
|
||||
let when = dispatch_time(DISPATCH_TIME_NOW, Int64(interval * Double(NSEC_PER_SEC)))
|
||||
|
||||
dispatch_after(when, dispatch_get_main_queue()) { [weak self] in
|
||||
if self?.isCancelled == false {
|
||||
handler()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func cancel() {
|
||||
isCancelled = true
|
||||
}
|
||||
}
|
@ -25,7 +25,7 @@ class RefreshLibraryOperation: GroupOperation {
|
||||
// 0.Download library
|
||||
let url = NSURL(string: "http://www.kiwix.org/library.xml")!
|
||||
let task = NSURLSession.sharedSession().dataTaskWithURL(url) { [unowned parseOperation] (data, response, error) -> Void in
|
||||
if let error = error {self.aggregateError(error)}
|
||||
if let error = error {self.addFatalError(error)}
|
||||
parseOperation.xmlData = data
|
||||
}
|
||||
let fetchOperation = URLSessionTaskOperation(task: task)
|
||||
@ -34,7 +34,8 @@ class RefreshLibraryOperation: GroupOperation {
|
||||
#if os(iOS) || os(watchOS) || os(tvOS)
|
||||
fetchOperation.addObserver(NetworkObserver())
|
||||
#endif
|
||||
fetchOperation.addCondition(ReachabilityCondition(host: url, allowCellular: Preference.libraryRefreshAllowCellularData))
|
||||
let reachibility = ReachabilityCondition(url: url, connectivity: Preference.libraryRefreshAllowCellularData ? .AnyConnectionKind : .ViaWiFi)
|
||||
fetchOperation.addCondition(reachibility)
|
||||
|
||||
if invokedAutomatically {
|
||||
addCondition(AllowAutoRefreshCondition())
|
||||
@ -45,8 +46,8 @@ class RefreshLibraryOperation: GroupOperation {
|
||||
parseOperation.addDependency(fetchOperation)
|
||||
}
|
||||
|
||||
override func finished(errors: [NSError]) {
|
||||
completionHandler?(errors: errors)
|
||||
override func operationDidFinish(errors: [ErrorType]) {
|
||||
completionHandler?(errors: [NSError]())
|
||||
}
|
||||
}
|
||||
|
||||
@ -129,22 +130,22 @@ class ParseLibraryOperation: Operation, NSXMLParserDelegate {
|
||||
}
|
||||
|
||||
private struct AllowAutoRefreshCondition: OperationCondition {
|
||||
static let name = "LibraryAllowAutoRefresh"
|
||||
static let isMutuallyExclusive = false
|
||||
let name = "LibraryAllowAutoRefresh"
|
||||
let isMutuallyExclusive = false
|
||||
|
||||
init() {}
|
||||
|
||||
func dependencyForOperation(operation: Operation) -> NSOperation? {
|
||||
private func dependencyForOperation(operation: Operation) -> NSOperation? {
|
||||
return nil
|
||||
}
|
||||
|
||||
func evaluateForOperation(operation: Operation, completion: OperationConditionResult -> Void) {
|
||||
private func evaluateForOperation(operation: Operation, completion: OperationConditionResult -> Void) {
|
||||
let allowAutoRefresh = !Preference.libraryAutoRefreshDisabled
|
||||
|
||||
if allowAutoRefresh {
|
||||
completion(.Satisfied)
|
||||
} else {
|
||||
let error = NSError(code: .ConditionFailed, userInfo: [OperationConditionKey: self.dynamicType.name])
|
||||
let error = NSError(domain: "", code: 1, userInfo: nil)
|
||||
completion(.Failed(error))
|
||||
}
|
||||
}
|
||||
|
@ -54,10 +54,10 @@ class ScanLocalBookOperation: Operation {
|
||||
updateCoreData()
|
||||
}
|
||||
|
||||
override func finished(errors: [NSError]) {
|
||||
override func operationDidFinish(errors: [ErrorType]) {
|
||||
context.performBlockAndWait {self.context.saveIfNeeded()}
|
||||
NSManagedObjectContext.mainQueueContext.performBlockAndWait {NSManagedObjectContext.mainQueueContext.saveIfNeeded()}
|
||||
NSOperationQueue.mainQueue().addOperationWithBlock {
|
||||
NSOperationQueue.mainQueue().addOperationWithBlock {
|
||||
self.completionHandler(currentZimFileURLSnapshot: self.currentZimFileURLSnapshot,
|
||||
currentIndexFolderURLSnapshot: self.currentIndexFolderURLSnapshot, firstBookAdded: self.firstBookAdded)
|
||||
}
|
||||
|
@ -41,8 +41,7 @@ class SearchOperation: GroupOperation {
|
||||
addCondition(MutuallyExclusive<ZimMultiReader>())
|
||||
}
|
||||
|
||||
override func finished(errors: [NSError]) {
|
||||
//print("Search Operation finished, status \(cancelled ? "Canceled" : "Not Canceled"), \(NSDate().timeIntervalSinceDate(startTime))")
|
||||
override func operationDidFinish(errors: [ErrorType]) {
|
||||
NSOperationQueue.mainQueue().addOperationWithBlock {
|
||||
self.completionHandler(self.cancelled ? nil : self.results)
|
||||
}
|
||||
@ -58,6 +57,7 @@ private class SingleBookSearchOperation: Operation {
|
||||
self.zimReader = zimReader
|
||||
self.lowerCaseSearchTerm = lowerCaseSearchTerm
|
||||
self.completionHandler = completionHandler
|
||||
super.init()
|
||||
}
|
||||
|
||||
override private func execute() {
|
||||
@ -80,6 +80,7 @@ private class SortSearchResultsOperation: Operation {
|
||||
|
||||
init(completionHandler: ([SearchResult]) -> Void) {
|
||||
self.completionHandler = completionHandler
|
||||
super.init()
|
||||
}
|
||||
|
||||
override private func execute() {
|
||||
|
@ -20,14 +20,15 @@ public class URLSessionDownloadTaskOperation: Operation {
|
||||
self.task = downloadTask
|
||||
super.init()
|
||||
|
||||
addObserver(BlockObserver(cancelHandler: { _ in
|
||||
addObserver(DidCancelObserver { _ in
|
||||
if self.produceResumeData {
|
||||
downloadTask.cancelByProducingResumeData({ (data) in
|
||||
})
|
||||
} else {
|
||||
downloadTask.cancel()
|
||||
}
|
||||
}))
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
public func cancel(produceResumeData produceResumeData: Bool) {
|
||||
|
@ -1,115 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2015 Apple Inc. All Rights Reserved.
|
||||
See LICENSE.txt for this sample’s licensing information
|
||||
|
||||
Abstract:
|
||||
This file shows an example of implementing the OperationCondition protocol.
|
||||
*/
|
||||
|
||||
import Foundation
|
||||
import SystemConfiguration
|
||||
import Operations
|
||||
|
||||
/**
|
||||
This is a condition that performs a very high-level reachability check.
|
||||
It does *not* perform a long-running reachability check, nor does it respond to changes in reachability.
|
||||
Reachability is evaluated once when the operation to which this is attached is asked about its readiness.
|
||||
*/
|
||||
struct ReachabilityCondition: OperationCondition {
|
||||
static let hostKey = "Host"
|
||||
static let name = "Reachability"
|
||||
static let isMutuallyExclusive = false
|
||||
|
||||
let host: NSURL
|
||||
let allowCellular: Bool
|
||||
|
||||
init(host: NSURL, allowCellular: Bool = true) {
|
||||
self.host = host
|
||||
self.allowCellular = allowCellular
|
||||
}
|
||||
|
||||
func dependencyForOperation(operation: Operation) -> NSOperation? {
|
||||
return nil
|
||||
}
|
||||
|
||||
func evaluateForOperation(operation: Operation, completion: OperationConditionResult -> Void) {
|
||||
ReachabilityController.requestReachability(host, allowCellular: allowCellular) { reachable in
|
||||
if reachable {
|
||||
completion(.Satisfied)
|
||||
}
|
||||
else {
|
||||
let userInfo = ["title": "Network Error",
|
||||
"message": "Unable connecting to the internet. Please check your connection."]
|
||||
let error = NSError(code: .ConditionFailed, userInfo: userInfo)
|
||||
completion(.Failed(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// A private singleton that maintains a basic cache of `SCNetworkReachability` objects.
|
||||
private class ReachabilityController {
|
||||
static var reachabilityRefs = [String: SCNetworkReachability]()
|
||||
|
||||
static let reachabilityQueue = dispatch_queue_create("Operations.Reachability", DISPATCH_QUEUE_SERIAL)
|
||||
|
||||
static func requestReachability(url: NSURL?, allowCellular: Bool, completionHandler: (Bool) -> Void) {
|
||||
if let host = url?.host {
|
||||
dispatch_async(reachabilityQueue) {
|
||||
var ref = self.reachabilityRefs[host]
|
||||
|
||||
if ref == nil {
|
||||
let hostString = host as NSString
|
||||
ref = SCNetworkReachabilityCreateWithName(nil, hostString.UTF8String)
|
||||
}
|
||||
|
||||
if let ref = ref {
|
||||
self.reachabilityRefs[host] = ref
|
||||
|
||||
let reachable = getReachibility(ref, allowCellular: allowCellular)
|
||||
completionHandler(reachable)
|
||||
} else {
|
||||
completionHandler(false)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Test for general internet connectibility
|
||||
dispatch_async(reachabilityQueue) {
|
||||
var zeroAddress = sockaddr_in()
|
||||
zeroAddress.sin_len = UInt8(sizeofValue(zeroAddress))
|
||||
zeroAddress.sin_family = sa_family_t(AF_INET)
|
||||
|
||||
guard let ref = withUnsafePointer(&zeroAddress, {
|
||||
SCNetworkReachabilityCreateWithAddress(nil, UnsafePointer($0))
|
||||
}) else {completionHandler(false); return}
|
||||
|
||||
let reachable = getReachibility(ref, allowCellular: allowCellular)
|
||||
completionHandler(reachable)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static func getReachibility(ref: SCNetworkReachability, allowCellular: Bool) -> Bool {
|
||||
var reachable = false
|
||||
var flags: SCNetworkReachabilityFlags = []
|
||||
if SCNetworkReachabilityGetFlags(ref, &flags) != false {
|
||||
/*
|
||||
Here to check forother considerations,
|
||||
such as whether or not the connection would require
|
||||
VPN, a cellular connection, etc.
|
||||
*/
|
||||
#if os(iOS) || os(watchOS) || os(tvOS)
|
||||
if allowCellular {
|
||||
reachable = flags.contains(.Reachable)
|
||||
} else {
|
||||
reachable = flags.contains(.Reachable) && !flags.contains(.IsWWAN)
|
||||
}
|
||||
#elseif os(OSX)
|
||||
return flags.contains(.Reachable)
|
||||
#endif
|
||||
|
||||
}
|
||||
return reachable
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user