diff --git a/Kiwix-iOS/AppDelegate.swift b/Kiwix-iOS/AppDelegate.swift
index a0dcead9..e209bd03 100644
--- a/Kiwix-iOS/AppDelegate.swift
+++ b/Kiwix-iOS/AppDelegate.swift
@@ -10,7 +10,7 @@ import CoreData
import Operations
@UIApplicationMain
-class AppDelegate: UIResponder, UIApplicationDelegate, OperationQueueDelegate {
+class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var mainController: MainController? {
diff --git a/Kiwix-iOS/Info.plist b/Kiwix-iOS/Info.plist
index 77c6331c..ab31dd59 100644
--- a/Kiwix-iOS/Info.plist
+++ b/Kiwix-iOS/Info.plist
@@ -49,7 +49,7 @@
CFBundleVersion
- 1.7.697
+ 1.7.699
ITSAppUsesNonExemptEncryption
LSRequiresIPhoneOS
diff --git a/Kiwix-iOS/Model/Network.swift b/Kiwix-iOS/Model/Network.swift
index f2dafbf6..df3d2e8b 100644
--- a/Kiwix-iOS/Model/Network.swift
+++ b/Kiwix-iOS/Model/Network.swift
@@ -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) {
diff --git a/Kiwix-iOSWidgets/Bookmarks/Info.plist b/Kiwix-iOSWidgets/Bookmarks/Info.plist
index 6cfac74e..3085c8d4 100644
--- a/Kiwix-iOSWidgets/Bookmarks/Info.plist
+++ b/Kiwix-iOSWidgets/Bookmarks/Info.plist
@@ -21,7 +21,7 @@
CFBundleSignature
????
CFBundleVersion
- 1.7.747
+ 1.7.768
NSExtension
NSExtensionMainStoryboard
diff --git a/Kiwix.xcodeproj/project.pbxproj b/Kiwix.xcodeproj/project.pbxproj
index e2e99f51..481bfb12 100644
--- a/Kiwix.xcodeproj/project.pbxproj
+++ b/Kiwix.xcodeproj/project.pbxproj
@@ -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 = ""; };
970C3DC91CBD79450026A240 /* MigrationPolicy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MigrationPolicy.swift; path = CoreData/Migration/MigrationPolicy.swift; sourceTree = ""; };
970C61961D34243600087758 /* URLSessionDownloadTaskOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = URLSessionDownloadTaskOperation.swift; path = Operations/URLSessionDownloadTaskOperation.swift; sourceTree = ""; };
- 970C61981D3429E400087758 /* ReachabilityCondition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReachabilityCondition.swift; sourceTree = ""; };
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 = ""; };
977998721C1E0B7900B1DD5E /* Language+CoreDataProperties.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "Language+CoreDataProperties.swift"; path = "Kiwix/CoreData/Language+CoreDataProperties.swift"; sourceTree = ""; };
9779987A1C1E1C9600B1DD5E /* Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Extensions.swift; path = Kiwix/Extensions.swift; sourceTree = ""; };
- 9779A1C21D34225E0071EFAB /* AlertOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AlertOperation.swift; path = Operations/AlertOperation.swift; sourceTree = ""; };
9779A1C31D34225E0071EFAB /* GlobalOperationQueue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GlobalOperationQueue.swift; path = Operations/GlobalOperationQueue.swift; sourceTree = ""; };
- 9779A1C41D34225E0071EFAB /* NetworkObserver.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = NetworkObserver.swift; path = Operations/NetworkObserver.swift; sourceTree = ""; };
9779A1C51D34225E0071EFAB /* RefreshLibraryOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RefreshLibraryOperation.swift; path = Operations/RefreshLibraryOperation.swift; sourceTree = ""; };
9779A1C61D34225E0071EFAB /* SearchOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SearchOperation.swift; path = Operations/SearchOperation.swift; sourceTree = ""; };
9779A1C71D34225E0071EFAB /* UIOperations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = UIOperations.swift; path = Operations/UIOperations.swift; sourceTree = ""; };
@@ -793,17 +789,6 @@
name = Shared;
sourceTree = "";
};
- 973DD4031D343F09009D45DB /* Basic */ = {
- isa = PBXGroup;
- children = (
- 9779A1C21D34225E0071EFAB /* AlertOperation.swift */,
- 9779A1C41D34225E0071EFAB /* NetworkObserver.swift */,
- 970C61981D3429E400087758 /* ReachabilityCondition.swift */,
- 9779A1C71D34225E0071EFAB /* UIOperations.swift */,
- );
- name = Basic;
- sourceTree = "";
- };
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 */,
);
diff --git a/Kiwix/Operations/AlertOperation.swift b/Kiwix/Operations/AlertOperation.swift
deleted file mode 100644
index 31ba58b6..00000000
--- a/Kiwix/Operations/AlertOperation.swift
+++ /dev/null
@@ -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())
- }
-
- 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)
- }
- }
-}
diff --git a/Kiwix/Operations/NetworkObserver.swift b/Kiwix/Operations/NetworkObserver.swift
deleted file mode 100644
index 60084e34..00000000
--- a/Kiwix/Operations/NetworkObserver.swift
+++ /dev/null
@@ -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
- }
-}
\ No newline at end of file
diff --git a/Kiwix/Operations/RefreshLibraryOperation.swift b/Kiwix/Operations/RefreshLibraryOperation.swift
index ee1034cd..988f1fac 100644
--- a/Kiwix/Operations/RefreshLibraryOperation.swift
+++ b/Kiwix/Operations/RefreshLibraryOperation.swift
@@ -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))
}
}
diff --git a/Kiwix/Operations/ScanLocalBookOperation.swift b/Kiwix/Operations/ScanLocalBookOperation.swift
index cb38e883..95e33c70 100644
--- a/Kiwix/Operations/ScanLocalBookOperation.swift
+++ b/Kiwix/Operations/ScanLocalBookOperation.swift
@@ -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)
}
diff --git a/Kiwix/Operations/SearchOperation.swift b/Kiwix/Operations/SearchOperation.swift
index 044d363a..cb12e6db 100644
--- a/Kiwix/Operations/SearchOperation.swift
+++ b/Kiwix/Operations/SearchOperation.swift
@@ -41,8 +41,7 @@ class SearchOperation: GroupOperation {
addCondition(MutuallyExclusive())
}
- 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() {
diff --git a/Kiwix/Operations/URLSessionDownloadTaskOperation.swift b/Kiwix/Operations/URLSessionDownloadTaskOperation.swift
index e88c5495..e462d321 100644
--- a/Kiwix/Operations/URLSessionDownloadTaskOperation.swift
+++ b/Kiwix/Operations/URLSessionDownloadTaskOperation.swift
@@ -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) {
diff --git a/Kiwix/ReachabilityCondition.swift b/Kiwix/ReachabilityCondition.swift
deleted file mode 100644
index 5d0fda75..00000000
--- a/Kiwix/ReachabilityCondition.swift
+++ /dev/null
@@ -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
- }
-}