I have this slightly popular Swift library called IJReachability up on Github. It checks the network connection status. Due to my office workload I've been very busy in the past few months so I couldn't attend to the project and keep in touch with the folks who are contributing.
Now I'm back and hoping to dust off the project, update to Swift 2 (probably still keep the 1.2 version in a separate branch) and activly participate on developing it.
The project was originally written in Swift 1.2:
import Foundation
import SystemConfiguration
public enum IJReachabilityType {
case WWAN,
WiFi,
NotConnected
}
public class IJReachability {
public class func isConnectedToNetwork() -> Bool {
var zeroAddress = sockaddr_in(sin_len: 0, sin_family: 0, sin_port: 0, sin_addr: in_addr(s_addr: 0), sin_zero: (0, 0, 0, 0, 0, 0, 0, 0))
zeroAddress.sin_len = UInt8(sizeofValue(zeroAddress))
zeroAddress.sin_family = sa_family_t(AF_INET)
let defaultRouteReachability = withUnsafePointer(&zeroAddress) {
SCNetworkReachabilityCreateWithAddress(nil, UnsafePointer($0)).takeRetainedValue()
}
var flags: SCNetworkReachabilityFlags = 0
if SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) == 0 {
return false
}
let isReachable = (flags & UInt32(kSCNetworkFlagsReachable)) != 0
let needsConnection = (flags & UInt32(kSCNetworkFlagsConnectionRequired)) != 0
return (isReachable && !needsConnection) ? true : false
}
public class func isConnectedToNetworkOfType() -> IJReachabilityType {
var zeroAddress = sockaddr_in(sin_len: 0, sin_family: 0, sin_port: 0, sin_addr: in_addr(s_addr: 0), sin_zero: (0, 0, 0, 0, 0, 0, 0, 0))
zeroAddress.sin_len = UInt8(sizeofValue(zeroAddress))
zeroAddress.sin_family = sa_family_t(AF_INET)
let defaultRouteReachability = withUnsafePointer(&zeroAddress) {
SCNetworkReachabilityCreateWithAddress(nil, UnsafePointer($0)).takeRetainedValue()
}
var flags: SCNetworkReachabilityFlags = 0
if SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) == 0 {
return .NotConnected
}
let isReachable = (flags & UInt32(kSCNetworkFlagsReachable)) != 0
let isWWAN = (flags & UInt32(kSCNetworkReachabilityFlagsIsWWAN)) != 0
if(isReachable && isWWAN){
return .WWAN
}
if(isReachable && !isWWAN){
return .WiFi
}
return .NotConnected
}
}
One method checks if you're currently connected to network or not and the other one returns the type of the connection. And as you can see there is quite a bit of code duplication.
I've updated the project to Swift 2 with the help of the pull requests I got:
import Foundation
import SystemConfiguration
let ReachabilityStatusChangedNotification = "ReachabilityStatusChangedNotification"
enum ReachabilityType: CustomStringConvertible {
case WWAN
case WiFi
case NotConnected
var description: String {
switch self {
case .WWAN: return "WWAN"
case .WiFi: return "WiFi"
case .NotConnected: return "NotConnected"
}
}
}
enum ReachabilityStatus: CustomStringConvertible {
case Offline
case Online
case Unknown
var description: String {
switch self {
case .Offline: return "Offline"
case .Online: return "Online"
case .Unknown: return "Unknown"
}
}
}
public class Reach {
func connectedToNetwork() -> (status: ReachabilityStatus, type: ReachabilityType) {
var zeroAddress = sockaddr_in()
zeroAddress.sin_len = UInt8(sizeofValue(zeroAddress))
zeroAddress.sin_family = sa_family_t(AF_INET)
guard let defaultRouteReachability = withUnsafePointer(&zeroAddress, {
SCNetworkReachabilityCreateWithAddress(nil, UnsafePointer($0))
}) else {
return (status: .Offline, type: .NotConnected)
}
var flags : SCNetworkReachabilityFlags = []
if !SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) {
return (status: .Offline, type: .NotConnected)
}
let isReachable = flags.contains(.Reachable)
let isWWAN = flags.contains(.IsWWAN)
if isReachable && isWWAN {
return (status: .Online, type: .WWAN)
}
if isReachable && !isWWAN {
return (status: .Online, type: .WiFi)
}
return (status: .Offline, type: .NotConnected)
}
func monitorReachabilityChanges() {
let host = "google.com"
var context = SCNetworkReachabilityContext(version: 0, info: nil, retain: nil, release: nil, copyDescription: nil)
let reachability = SCNetworkReachabilityCreateWithName(nil, host)!
SCNetworkReachabilitySetCallback(reachability, { (_, flags, _) in
var status: ReachabilityStatus!
var type: ReachabilityType!
let connectionRequired = flags.contains(.ConnectionRequired)
let isReachable = flags.contains(.Reachable)
let isWWAN = flags.contains(.IsWWAN)
if !connectionRequired && flags.contains(.Reachable) {
if isReachable && isWWAN {
status = .Online
type = .WWAN
}
if isReachable && !isWWAN {
status = .Online
type = .WiFi
}
} else {
status = .Offline
type = .NotConnected
}
NSNotificationCenter.defaultCenter().postNotificationName(ReachabilityStatusChangedNotification,
object: nil,
userInfo: ["Status": status.description, "Type": type.description])
}, &context)
SCNetworkReachabilityScheduleWithRunLoop(reachability, CFRunLoopGetMain(), kCFRunLoopCommonModes)
}
}
But I did something different. Instead of having two functions for the network status and the type, I consolidated the functionality of both functions into one. I also added a new function to monitor the network connectivity in the background (this wasn't possible in Swift 1.2 due to language limitations).
I have two questions:
- The
connectedToNetwork()
function returns a tuple packing both the status and type. Is this a good way to do this? Even though this is possible, I've never seen tuples used much in Apple and third party frameworks/libraries. - There is still some code duplication. Specifically checking the
flags
variable for what it contains. I'm not sure how to refactor this in an optimal way.