无法调用 'copyBytes' & "C-style for statement has been removed in Swift 3" 尝试将项目更新到 swift 3


extension String {
/// Create NSData from hexadecimal string representation
///
/// This takes a hexadecimal representation and creates a NSData object. Note, if the string has any spaces, those are removed. Also if the string started with a '<' or ended with a '>', those are removed, too. This does no validation of the string to ensure it's a valid hexadecimal string
///
/// The use of `strtoul` inspired by Martin R at http://stackoverflow.com/a/26284562/1271826
///
/// - returns: NSData represented by this hexadecimal string. Returns nil if string contains characters outside the 0-9 and a-f range.
func dataFromHexadecimalString() -> NSData? {
let trimmedString = self.stringByTrimmingCharactersInSet(NSCharacterSet(charactersInString: "<> ")).stringByReplacingOccurrencesOfString(" ", withString: "")
// make sure the cleaned up string consists solely of hex digits, and that we have even number of them
var error: NSError?
let regex: NSRegularExpression?
do {
regex = try NSRegularExpression(pattern: "^[0-9a-f]*$", options: .CaseInsensitive)
} catch let error1 as NSError {
error = error1
regex = nil
}
let found = regex?.firstMatchInString(trimmedString, options: [], range: NSMakeRange(0, trimmedString.characters.count))
if found == nil || found?.range.location == NSNotFound || trimmedString.characters.count % 2 != 0 {
return nil
}
// everything ok, so now let's build NSData
let data = NSMutableData(capacity: trimmedString.characters.count / 2)
for var index = trimmedString.startIndex; index < trimmedString.endIndex; index = index.successor().successor() {
let byteString = trimmedString.substringWithRange(Range<String.Index>(start: index, end: index.successor().successor()))
let num = UInt8(byteString.withCString { strtoul($0, nil, 16) })
data?.appendBytes([num] as [UInt8], length: 1)
}
return data
}
}

尝试将上述代码中的 for 循环转换为 swift 3,目前是用 swift 2.3 编写的,但遇到了问题。错误是:"C 样式的语句已在 Swift 3 中删除">

下面的 for 循环是我在 xcode 上按下"转换为 swift 3"按钮后发生的事情。

for var index = trimmedString.startIndex; index < trimmedString.endIndex; index = <#T##Collection corresponding to your index##Collection#>.index(after: <#T##Collection corresponding to `index`##Collection#>.index(after: index)) {
let byteString = trimmedString.substring(with: (index ..< <#T##Collection corresponding to your index##Collection#>.index(after: <#T##Collection corresponding to `index`##Collection#>.index(after: index))))
let num = UInt8(byteString.withCString { strtoul($0, nil, 16) })
data?.append([num] as [UInt8], length: 1)
}

extension NSData {
/// Create hexadecimal string representation of NSData object.
///
/// - returns: String representation of this NSData object.
func hexadecimalString() -> String {
let string = NSMutableString(capacity: length * 2)
var byte: UInt8 = 0
for i in 0 ..< length {
getBytes(&byte, range: NSMakeRange(i, 1))
string.appendFormat("%02x", byte)
}
return string as String
}
}

此外,上述代码片段中的 for 循环在 swift 3 中不起作用。如何为 swift 3 重写它?这个错误是:"无法使用类型为'(to: inout UInt8, from: NSRange)'的参数列表调用'copyBytes'">

任何帮助表示赞赏。我使用这些函数为我正在使用的第三方服务构建一个特殊的 url,但正在努力将这种复杂的语法更新为 swift 3。

此处的错误屏幕截图

有许多线程解释了如何转换 C 风格的 for 循环,或者如何在 Swift 3 中使用Data。(在 Swift 3 中,你最好使用Data而不是NSData。您只需要找到并组合它们。

extension String {
func dataFromHexadecimalString() -> Data? {
let trimmedString = self.trimmingCharacters(in: CharacterSet(charactersIn: "<> ")).replacingOccurrences(of: " ", with: "")
//`NSRegularExpression(pattern:options:)` will not throw error for a valid pattern & options.
//And you need to use `utf16.count` when working with `NSRegularExpression`.
let regex = try! NSRegularExpression(pattern: "^[0-9a-f]*$", options: .caseInsensitive)
let found = regex.firstMatch(in: trimmedString, range: NSMakeRange(0, trimmedString.utf16.count))
if found == nil || found!.range.location == NSNotFound || trimmedString.characters.count % 2 != 0 {
return nil
}
//In Swift 3, working with `Data` is easier than `NSData` in most cases.
var data = Data(capacity: trimmedString.characters.count / 2)
//Generally, `for INIT; COND; UPDATE {...}` can be re-written with `INIT; while COND {...; UPDATE}`
var index = trimmedString.startIndex
while index < trimmedString.endIndex {
let nextIndex = trimmedString.characters.index(index, offsetBy: 2)
let byteString = trimmedString.substring(with: index..<nextIndex)
let num = UInt8(byteString, radix: 16)!
data.append(num)
index = nextIndex
}
return data
}
}
extension Data {
func hexadecimalString() -> String {
var string = ""
string.reserveCapacity(count * 2)
//You have no need to use `getBytes(_:range:)` when you use each byte of Data one by one.
for byte in self {
string.append(String(format: "%02X", byte))
}
return string
}
}

有些部分可以用更 Swifty 的方式重写,但我保留了代码的一些基本结构,以便于比较两个代码。

最新更新