DispatchQueue 闭包中的字符串插值警告
String interpolation warning in DispatchQueue closure
假设我得到以下代码,它工作正常。
override func viewDidLoad() {
super.viewDidLoad()
// 1. put loadLevel() in background queue
DispatchQueue.global().async { [weak self] in
self?.loadLevel()
}
}
func loadLevel() {
var clueString = ""
var solutionString = ""
var letterBits = [String]()
// 2. some heavy code here
DispatchQueue.main.async { [weak self] in
// 3. push some UI code back to main thread
}
但是,当我将后台队列移动到 loadLevel() 内部并覆盖繁重的代码和 UI 代码时,我遇到一个问题,即在启动应用程序时 UI 更新为空值.那么这两种方式有什么不同呢?
override func viewDidLoad() {
super.viewDidLoad()
// 1. call loadLevel
loadLevel()
}
func loadLevel() {
var clueString = ""
var solutionString = ""
var letterBits = [String]()
DispatchQueue.global().async { [weak self] in
// 2. some heavy code in background queue
DispatchQueue.main.async {
// 3. push UI code back to main thread
}
}
}
用里面的重代码更新第二个代码。
我发现了这个问题,它实际上与 GCD 无关。此问题在行 Bundle.main.url(forResource: "level\(self?.level)"
中,它会产生字符串插值警告。结果资源加载得到 nil
我猜。
因为我在这里使用弱引用[weak self]作为捕获列表,所以我需要在全局变量level
之前放置self?
,以防在闭包中使用它。如果我给它一个像 \(self?.level ?? 0)
这样的默认值,那么这个问题就解决了。
但是这里是属性处理这个String插值的方式吗?或者这里应该涉及一些更好的方法?
override func viewDidLoad() {
super.viewDidLoad()
// 1. call loadLevel
loadLevel()
}
func loadLevel() {
var clueString = ""
var solutionString = ""
var letterBits = [String]()
DispatchQueue.global().async { [weak self] in
if let levelFileURL = Bundle.main.url(forResource: "level\(self?.level)", withExtension: "txt") {
if let levelContents = try? String(contentsOf: levelFileURL) {
var lines = levelContents.components(separatedBy: "\n")
lines.shuffle()
self?.correctGuess = 0
print("AAA")
for (index, line) in lines.enumerated() {
let parts = line.components(separatedBy: ": ")
let answer = parts[0]
let clue = parts[1]
clueString += "\(index + 1). \(clue)\n"
let solutionWord = answer.replacingOccurrences(of: "|", with: "")
solutionString += "\(solutionWord.count) letters\n"
self?.solutions.append(solutionWord)
let bits = answer.components(separatedBy: "|")
letterBits += bits
print("ABC")
}
}
}
DispatchQueue.main.async {
// 3. push UI code back to main thread
}
}
}
首先让我说,我不知道,但我有一个想法供您测试。将 DispatchQueue.global().async
移动到 loadLevel()
.
的第一行
func loadLevel() {
DispatchQueue.global().async { [weak self] in
var clueString = ""
var solutionString = ""
var letterBits = [String]()
// 2. some heavy code in background queue
DispatchQueue.main.async {
// 3. push UI code back to main thread
}
}
}
这将更改隔离为仅调用 loadLevel()
。如果这按预期工作,则继续向下移动 DispatchQueue.global().async
调用直到它中断。
func loadLevel() {
var clueString = ""
DispatchQueue.global().async { [weak self] in
var solutionString = ""
var letterBits = [String]()
// 2. some heavy code in background queue
DispatchQueue.main.async {
// 3. push UI code back to main thread
}
}
}
您参考了:
let resource = Bundle.main.url(forResource: "level\(self?.level)" withExtension: ...)
警告是
String interpolation produces a debug description for an optional value; did you mean to make this explicit?
编译器警告您正在执行可选值的字符串插值。
让我们考虑一个更简单的示例,以显示当您使用可选值进行字符串插值时会发生什么:
print("\(self?.level)")
如果级别是xxx
,它会打印
Optional("xxx")
显然,如果 self
或 level
是可选的,它只会说:
nil
显然,这些都不是您想要的。所以,打开可选的。例如
guard let level = self?.level else { return }
let resource = Bundle.main.url(forResource: "level\(level)" withExtension: ...)
假设我得到以下代码,它工作正常。
override func viewDidLoad() {
super.viewDidLoad()
// 1. put loadLevel() in background queue
DispatchQueue.global().async { [weak self] in
self?.loadLevel()
}
}
func loadLevel() {
var clueString = ""
var solutionString = ""
var letterBits = [String]()
// 2. some heavy code here
DispatchQueue.main.async { [weak self] in
// 3. push some UI code back to main thread
}
但是,当我将后台队列移动到 loadLevel() 内部并覆盖繁重的代码和 UI 代码时,我遇到一个问题,即在启动应用程序时 UI 更新为空值.那么这两种方式有什么不同呢?
override func viewDidLoad() {
super.viewDidLoad()
// 1. call loadLevel
loadLevel()
}
func loadLevel() {
var clueString = ""
var solutionString = ""
var letterBits = [String]()
DispatchQueue.global().async { [weak self] in
// 2. some heavy code in background queue
DispatchQueue.main.async {
// 3. push UI code back to main thread
}
}
}
用里面的重代码更新第二个代码。
我发现了这个问题,它实际上与 GCD 无关。此问题在行 Bundle.main.url(forResource: "level\(self?.level)"
中,它会产生字符串插值警告。结果资源加载得到 nil
我猜。
因为我在这里使用弱引用[weak self]作为捕获列表,所以我需要在全局变量level
之前放置self?
,以防在闭包中使用它。如果我给它一个像 \(self?.level ?? 0)
这样的默认值,那么这个问题就解决了。
但是这里是属性处理这个String插值的方式吗?或者这里应该涉及一些更好的方法?
override func viewDidLoad() {
super.viewDidLoad()
// 1. call loadLevel
loadLevel()
}
func loadLevel() {
var clueString = ""
var solutionString = ""
var letterBits = [String]()
DispatchQueue.global().async { [weak self] in
if let levelFileURL = Bundle.main.url(forResource: "level\(self?.level)", withExtension: "txt") {
if let levelContents = try? String(contentsOf: levelFileURL) {
var lines = levelContents.components(separatedBy: "\n")
lines.shuffle()
self?.correctGuess = 0
print("AAA")
for (index, line) in lines.enumerated() {
let parts = line.components(separatedBy: ": ")
let answer = parts[0]
let clue = parts[1]
clueString += "\(index + 1). \(clue)\n"
let solutionWord = answer.replacingOccurrences(of: "|", with: "")
solutionString += "\(solutionWord.count) letters\n"
self?.solutions.append(solutionWord)
let bits = answer.components(separatedBy: "|")
letterBits += bits
print("ABC")
}
}
}
DispatchQueue.main.async {
// 3. push UI code back to main thread
}
}
}
首先让我说,我不知道,但我有一个想法供您测试。将 DispatchQueue.global().async
移动到 loadLevel()
.
func loadLevel() {
DispatchQueue.global().async { [weak self] in
var clueString = ""
var solutionString = ""
var letterBits = [String]()
// 2. some heavy code in background queue
DispatchQueue.main.async {
// 3. push UI code back to main thread
}
}
}
这将更改隔离为仅调用 loadLevel()
。如果这按预期工作,则继续向下移动 DispatchQueue.global().async
调用直到它中断。
func loadLevel() {
var clueString = ""
DispatchQueue.global().async { [weak self] in
var solutionString = ""
var letterBits = [String]()
// 2. some heavy code in background queue
DispatchQueue.main.async {
// 3. push UI code back to main thread
}
}
}
您参考了:
let resource = Bundle.main.url(forResource: "level\(self?.level)" withExtension: ...)
警告是
String interpolation produces a debug description for an optional value; did you mean to make this explicit?
编译器警告您正在执行可选值的字符串插值。
让我们考虑一个更简单的示例,以显示当您使用可选值进行字符串插值时会发生什么:
print("\(self?.level)")
如果级别是xxx
,它会打印
Optional("xxx")
显然,如果 self
或 level
是可选的,它只会说:
nil
显然,这些都不是您想要的。所以,打开可选的。例如
guard let level = self?.level else { return }
let resource = Bundle.main.url(forResource: "level\(level)" withExtension: ...)