在Swift 3中将数据转换为字符串

31

我对Swift非常陌生。

我想为我的教育应用程序创建类似API的东西。

我有这段代码:

static func getFilm(filmID: Int) -> String {
    
    print("getFilm")
    
    let url = URL(string: "https://api.kinopoisk.cf/getFilm?filmID=\(filmID)")!
    var request = URLRequest(url: url)
    
    var returnData: String = ""
    
    let task = URLSession.shared.dataTask(with: request) { data, response, error in
        if var responseVar = response, var dataVar = data {
            print(responseVar)
            returnData = String(data: dataVar, encoding: .utf8)
        } else {
            print(error)
        }
    }
    
    task.resume()
    
    return returnData
}
在这一行中,我尝试将Data转换为String: returnData = String(data: dataVar, encoding: .utf8) Swift编译器给出了一个错误,并将此行更改为: returnData = String(data: dataVar, encoding: .utf8)! 当我执行这行时,我得到一个空的returnData变量。
如果我使用基本的示例行: print(String(data: data, encoding: .utf8)) 一切都正常,我可以在XCode控制台中看到data。
那么,我该如何将Data转换为String?

主要问题在于你无法从异步函数中返回任何东西。你需要一个完成处理程序。 - vadian
@vadian 你可以帮我把我的代码转成代码完成处理器吗?我已经读了很多关于它们的文章,但是我不理解需要在我的代码中分离什么。 - IlyaGutnikov
我写了一个回答。 - vadian
4个回答

52
这是一个使用完成处理程序的示例:
class func getFilm(filmID: Int, completion: @escaping (String) -> ()) {
    let url = URL(string: "https://api.kinopoisk.cf/getFilm?filmID=\(filmID)")!
    
    URLSession.shared.dataTask(with:url) { (data, response, error) in
      if error != nil {
        print(error!)
        completion("")
      } else {
        if let returnData = String(data: data!, encoding: .utf8) {
          completion(returnData)
        } else {
          completion("")
        }
      }
    }.resume()
}

你称之为
MyClass.getFilm(filmID:12345) { result in
   print(result)
}

如果发生错误,完成处理程序将返回一个空字符串。 MyClassgetFilm 方法的封闭类。很可能网络服务会返回 JSON 数据,所以您可能需要将 JSON 反序列化为数组或字典。
在一个更复杂的版本中,创建一个具有两个情况和相关值的枚举。
enum ConnectionResult {
  case success(String), failure(Error)
}

通过更多努力展示Swift的微妙力量,您可以在单个对象中返回转换后的字符串成功或失败时的错误。

class func getFilm(filmID: Int, completion: @escaping (ConnectionResult) -> ()) {
    let url = URL(string: "https://api.kinopoisk.cf/getFilm?filmID=\(filmID)")!
    
    URLSession.shared.dataTask(with:url) { (data, response, error) in
      if error != nil {
        completion(.failure(error!))
      } else {
        if let returnData = String(data: data!, encoding: .utf8) {
          completion(.success(returnData))
        } else {
          completion(.failure(NSError(domain: "myDomain", code: 9999, userInfo: [NSLocalizedDescriptionKey : "The data is not converible to 'String'"])))
        }
      }
    }.resume()
}

在调用方,一个switch语句将各个情况分开。
MyClass.getFilm(filmID:12345) { result in
    switch result {
    case .success(let string) : print(string)
    case .failure(let error) : print(error)
    }
}

与此同时,在Swift 5.5+中使用async/await,它变得更加舒适。
class func getFilm(filmID: Int) async throws -> String {
    print("getFilm")
    
    let url = URL(string: "https://api.kinopoisk.cf/getFilm?filmID=\(filmID)")!
    let (data, _) = try await URLSession.shared.data(from: url)
    return String(data: data, encoding: .utf8)!
}

不好意思,我不理解如何从getFilm获取返回值。我的意思是这样var test = getFilm() - IlyaGutnikov
你的 MyClass.getFilm(filmID:12345) { result in print(result) } 代码让我大开眼界。我以为它会很简单 - 我有带输入和输出参数的函数,并且我知道如何在外部代码中获取 result - IlyaGutnikov
我认为真正令人困惑的是result in print(result)如何注入到completion(returnData)中。我希望能更详细地解释这个魔法是如何发生的。 - Houman
@Houman,“result”是“(result: Result) -> ()”的简写形式。completion调用将带有适当的“Result”参数的闭包传递。 - vadian
很多错误。无法作为类实现。如果这样做:无法调用非函数类型的“String”值。 - J A S K I E R
@Oleksandr 该代码应在类MyClass中执行。在视图控制器中,也可以作为实例方法使用,无需使用class关键字。 - vadian

3

对于未来可能不感兴趣于楼主电影代码的读者;

简单来说,可以尝试这样做:

extension Data {
    public func toString() -> String {
        return String(data: self, encoding: .utf8) ?? "";
    }
}

也请查看我关于toHex的相关回答


3

我遇到了这个问题,如果对于不可预测的数据使用encoding: .utf8是无效的。它每次都会返回nil

请改用以下方法:

String(decoding: data, as: UTF8.self)


如果数据是不可预测的,它会返回什么? - RainCast

0
如果您知道一个 Data 实例包含一个字符串并且想要进行转换,您应该使用 String(decoding:as:) 初始化器,像这样: let str = String(decoding: data, as: UTF8.self)
如果 Data 实例无法转换为 UTF-8 字符串,则会返回一个空字符串。这意味着您需要知道用于存储字符串的格式,但通常最好选择 UTF-8。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接