Swift 为 iOS 项目构建 IP 4 地址 class
Swift Building IP 4 address class for a iOS project
我试图为 IP 地址创建自己的 class。我想将其用于 iOS 项目。我试图弄清楚是否要将代码放在 0 到 255 之间。分隔符无法正常工作。我希望它保存一个像 192.168.0.1 这样的 IP 地址,如果我输入 400.168.0.1 它应该 return 一个错误或者说请输入一个真实的 IP 地址作为输出之一,这是错误的。我试图创建一个 class,当你输入一个 ip 地址时,它应该保存在 class 本身中。我想稍后制作一个 iOS 应用程序,这将帮助人们了解如何为 cisco 路由器和交换机分配 IP 地址。基本上想制作一个应用程序来帮助使用 CIDR ip 地址符号的人,比如我在网上找到的这个网页程序,但如果没有互联网连接我几乎无法使用。 http://jodies.de/ipcalc 如果我可以编写一个移动应用程序来执行此网站的操作,那将非常适合我在网络方面的工作。
import UIKit
class IP4 {
var ipA: Int?
var ipB: Int?
var ipC: Int?
var ipD: Int?
func fullIP() -> Int {
var parts: [Int] = []
if let ipA = self.ipA {
parts += [ipA]
}
if let ipB = self.ipB {
parts += [ipB]
}
if let ipC = self.ipC {
parts += [ipC]
}
if let ipD = self.ipD {
parts += [ipD]
}
return parts.joined(separator: ".")
}
}
let ipaddress = IP4()
ipaddress.ipA = 223
ipaddress.ipB = 9
ipaddress.ipC = 50
ipaddress.ipD = 60
这是一个示例,可以在Playground上进行测试。 (在 Xcode 9.4.1 上测试。)
import Foundation
struct IPv4: CustomStringConvertible, Equatable, Hashable {
enum Errors: Error {
case invalidFormat
case octetOutOfRange
}
var ipA: UInt8
var ipB: UInt8
var ipC: UInt8
var ipD: UInt8
init() {
ipA = 0
ipB = 0
ipC = 0
ipD = 0
}
init(_ ipA: UInt8, _ ipB: UInt8, _ ipC: UInt8, _ ipD: UInt8) {
self.ipA = ipA
self.ipB = ipB
self.ipC = ipC
self.ipD = ipD
}
private static let parsingRegex = try! NSRegularExpression(pattern: "^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$")
init(_ ipString: String) throws {
guard let match = IPv4.parsingRegex.firstMatch(in: ipString, range: NSRange(0..<ipString.utf16.count)) else {
throw Errors.invalidFormat
}
let strA = ipString[Range(match.range(at: 1), in: ipString)!]
let strB = ipString[Range(match.range(at: 2), in: ipString)!]
let strC = ipString[Range(match.range(at: 3), in: ipString)!]
let strD = ipString[Range(match.range(at: 4), in: ipString)!]
guard
let ipA = UInt8(strA),
let ipB = UInt8(strB),
let ipC = UInt8(strC),
let ipD = UInt8(strD)
else {throw Errors.octetOutOfRange}
self.ipA = ipA
self.ipB = ipB
self.ipC = ipC
self.ipD = ipD
}
var description: String {
return "\(ipA).\(ipB).\(ipC).\(ipD)"
}
var networkBytes: Data {
return Data(bytes: [ipA, ipB, ipC, ipD])
}
var hostWord: UInt32 {
return UInt32(ipA) << 24 + UInt32(ipB) << 16 + UInt32(ipC) << 8 + UInt32(ipD)
}
}
let ip = IPv4(223, 9, 50, 60)
print(ip) //->223.9.50.60
do {
let ip = try IPv4("400.168.0.1")
print(ip)
} catch {
print(error) //->octetOutOfRange
}
更好地使用 struct
而不是 class
。因为它的相等性应该由它的内容来判断,而不是它在堆中的地址。
IPv4 地址由 4 个八位字节组成。你最好使用UInt8
,非可选。任何部分都不能为nil。
没有可以容纳 3 位小数的数字类型。如果你想生成像 192.168.0.1
这样的符号,它需要是 String
.
我准备了3种输出。仔细想想你想要哪一个。
同时查找我的代码的哪一部分正在实施 如果我输入 400.168.0.1 它应该 return 一个错误.
我向您展示了我的 struct
的一些扩展,这可能有助于实现链接站点中显示的类似功能。
要进行二进制表示:
extension UInt8 {
var fixedBinaryDescription: String {
let binStr = String(self, radix: 2)
return String(repeating: "0", count: 8-binStr.count) + binStr
}
}
extension IPv4 {
var binaryDescription: String {
return "\(ipA.fixedBinaryDescription).\(ipB.fixedBinaryDescription).\(ipC.fixedBinaryDescription).\(ipD.fixedBinaryDescription)"
}
}
print(ip.binaryDescription) //->11011111.00001001.00110010.00111100
要使用遮罩:
extension IPv4 {
init(maskOfLength len: Int) {
let highBits: [UInt8] = [
0b10000000,
0b11000000,
0b11100000,
0b11110000,
0b11111000,
0b11111100,
0b11111110,
0b11111111,
]
switch len {
case 0:
self = IPv4(0, 0, 0, 0)
case 1...8:
self = IPv4(highBits[len-1], 0, 0, 0)
case 9...16:
self = IPv4(0b11111111, highBits[len-9], 0, 0)
case 17...24:
self = IPv4(0b11111111, 0b11111111, highBits[len-17], 0)
case 25...32:
self = IPv4(0b11111111, 0b11111111, 0b11111111, highBits[len-25])
default:
fatalError()
}
}
func masked(by mask: IPv4) -> IPv4 {
return IPv4(self.ipA & mask.ipA, self.ipB & mask.ipB, self.ipC & mask.ipC, self.ipD & mask.ipD)
}
}
let mask = IPv4(maskOfLength: 24)
print(mask.binaryDescription) //->11111111.11111111.11111111.00000000
print(ip.masked(by: mask).binaryDescription) //->11011111.00001001.00110010.00000000
获取 IP v4 地址 class 的扩展。
enum IPv4AddressClass {
case a
case b
case c
case d
case e
}
extension IPv4 {
var addressClass: IPv4AddressClass {
if ipA & 0b1_0000000 == 0b0_0000000 {
return .a
} else if ipA & 0b11_000000 == 0b10_000000 {
return .b
} else if ipA & 0b111_00000 == 0b110_00000 {
return .c
} else if ipA & 0b1111_0000 == 0b1110_0000 {
return .d
} else {
return .e
}
}
}
print(ip.addressClass) //->c
我试图为 IP 地址创建自己的 class。我想将其用于 iOS 项目。我试图弄清楚是否要将代码放在 0 到 255 之间。分隔符无法正常工作。我希望它保存一个像 192.168.0.1 这样的 IP 地址,如果我输入 400.168.0.1 它应该 return 一个错误或者说请输入一个真实的 IP 地址作为输出之一,这是错误的。我试图创建一个 class,当你输入一个 ip 地址时,它应该保存在 class 本身中。我想稍后制作一个 iOS 应用程序,这将帮助人们了解如何为 cisco 路由器和交换机分配 IP 地址。基本上想制作一个应用程序来帮助使用 CIDR ip 地址符号的人,比如我在网上找到的这个网页程序,但如果没有互联网连接我几乎无法使用。 http://jodies.de/ipcalc 如果我可以编写一个移动应用程序来执行此网站的操作,那将非常适合我在网络方面的工作。
import UIKit
class IP4 {
var ipA: Int?
var ipB: Int?
var ipC: Int?
var ipD: Int?
func fullIP() -> Int {
var parts: [Int] = []
if let ipA = self.ipA {
parts += [ipA]
}
if let ipB = self.ipB {
parts += [ipB]
}
if let ipC = self.ipC {
parts += [ipC]
}
if let ipD = self.ipD {
parts += [ipD]
}
return parts.joined(separator: ".")
}
}
let ipaddress = IP4()
ipaddress.ipA = 223
ipaddress.ipB = 9
ipaddress.ipC = 50
ipaddress.ipD = 60
这是一个示例,可以在Playground上进行测试。 (在 Xcode 9.4.1 上测试。)
import Foundation
struct IPv4: CustomStringConvertible, Equatable, Hashable {
enum Errors: Error {
case invalidFormat
case octetOutOfRange
}
var ipA: UInt8
var ipB: UInt8
var ipC: UInt8
var ipD: UInt8
init() {
ipA = 0
ipB = 0
ipC = 0
ipD = 0
}
init(_ ipA: UInt8, _ ipB: UInt8, _ ipC: UInt8, _ ipD: UInt8) {
self.ipA = ipA
self.ipB = ipB
self.ipC = ipC
self.ipD = ipD
}
private static let parsingRegex = try! NSRegularExpression(pattern: "^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$")
init(_ ipString: String) throws {
guard let match = IPv4.parsingRegex.firstMatch(in: ipString, range: NSRange(0..<ipString.utf16.count)) else {
throw Errors.invalidFormat
}
let strA = ipString[Range(match.range(at: 1), in: ipString)!]
let strB = ipString[Range(match.range(at: 2), in: ipString)!]
let strC = ipString[Range(match.range(at: 3), in: ipString)!]
let strD = ipString[Range(match.range(at: 4), in: ipString)!]
guard
let ipA = UInt8(strA),
let ipB = UInt8(strB),
let ipC = UInt8(strC),
let ipD = UInt8(strD)
else {throw Errors.octetOutOfRange}
self.ipA = ipA
self.ipB = ipB
self.ipC = ipC
self.ipD = ipD
}
var description: String {
return "\(ipA).\(ipB).\(ipC).\(ipD)"
}
var networkBytes: Data {
return Data(bytes: [ipA, ipB, ipC, ipD])
}
var hostWord: UInt32 {
return UInt32(ipA) << 24 + UInt32(ipB) << 16 + UInt32(ipC) << 8 + UInt32(ipD)
}
}
let ip = IPv4(223, 9, 50, 60)
print(ip) //->223.9.50.60
do {
let ip = try IPv4("400.168.0.1")
print(ip)
} catch {
print(error) //->octetOutOfRange
}
更好地使用
struct
而不是class
。因为它的相等性应该由它的内容来判断,而不是它在堆中的地址。IPv4 地址由 4 个八位字节组成。你最好使用
UInt8
,非可选。任何部分都不能为nil。没有可以容纳 3 位小数的数字类型。如果你想生成像
192.168.0.1
这样的符号,它需要是String
.
我准备了3种输出。仔细想想你想要哪一个。
同时查找我的代码的哪一部分正在实施 如果我输入 400.168.0.1 它应该 return 一个错误.
我向您展示了我的 struct
的一些扩展,这可能有助于实现链接站点中显示的类似功能。
要进行二进制表示:
extension UInt8 {
var fixedBinaryDescription: String {
let binStr = String(self, radix: 2)
return String(repeating: "0", count: 8-binStr.count) + binStr
}
}
extension IPv4 {
var binaryDescription: String {
return "\(ipA.fixedBinaryDescription).\(ipB.fixedBinaryDescription).\(ipC.fixedBinaryDescription).\(ipD.fixedBinaryDescription)"
}
}
print(ip.binaryDescription) //->11011111.00001001.00110010.00111100
要使用遮罩:
extension IPv4 {
init(maskOfLength len: Int) {
let highBits: [UInt8] = [
0b10000000,
0b11000000,
0b11100000,
0b11110000,
0b11111000,
0b11111100,
0b11111110,
0b11111111,
]
switch len {
case 0:
self = IPv4(0, 0, 0, 0)
case 1...8:
self = IPv4(highBits[len-1], 0, 0, 0)
case 9...16:
self = IPv4(0b11111111, highBits[len-9], 0, 0)
case 17...24:
self = IPv4(0b11111111, 0b11111111, highBits[len-17], 0)
case 25...32:
self = IPv4(0b11111111, 0b11111111, 0b11111111, highBits[len-25])
default:
fatalError()
}
}
func masked(by mask: IPv4) -> IPv4 {
return IPv4(self.ipA & mask.ipA, self.ipB & mask.ipB, self.ipC & mask.ipC, self.ipD & mask.ipD)
}
}
let mask = IPv4(maskOfLength: 24)
print(mask.binaryDescription) //->11111111.11111111.11111111.00000000
print(ip.masked(by: mask).binaryDescription) //->11011111.00001001.00110010.00000000
获取 IP v4 地址 class 的扩展。
enum IPv4AddressClass {
case a
case b
case c
case d
case e
}
extension IPv4 {
var addressClass: IPv4AddressClass {
if ipA & 0b1_0000000 == 0b0_0000000 {
return .a
} else if ipA & 0b11_000000 == 0b10_000000 {
return .b
} else if ipA & 0b111_00000 == 0b110_00000 {
return .c
} else if ipA & 0b1111_0000 == 0b1110_0000 {
return .d
} else {
return .e
}
}
}
print(ip.addressClass) //->c