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 - } -}