你能相信吗? 我有一个像这样的循环(请原谅任何错误,我不得不大量删除了许多信息和变量名,请相信它是有效的)。
...旧示例已编辑,见下面的代码...
如果我将那些中间的str = "Blah \(odat.count)" + str
类型的行更改为str = str + "Blah \(odat.count)"
,用户界面就会停止响应,我得到一个彩色的圆形指针。NSTextField确实会到达第一个self.display.string...
,但然后就会冻结。
由于我不熟悉多线程编程,所以请随意纠正我的方法。希望我想要实现的内容是清楚的。
我必须承认,工作版本也有点卡顿,但从来没有真正的死机过。 典型值为n=70,var3=7。
编辑:
这里是一个完全可用的示例。只需连接文本视图、进度条和按钮即可。尝试在主函数之间进行切换。
//
// Controllers.swift
//
//
import Cocoa
class MainController: NSObject {
@IBOutlet var display: NSTextView!
@IBOutlet weak var prog: NSProgressIndicator!
@IBAction func go1(sender: AnyObject) {
theRoutine(70)
}
@IBAction func go2(sender: AnyObject) {
theRoutine(50)
}
class SomeClass {
var x: Int
var y: Int
var p: Double
init?(size: Int, pro: Double) {
x = size
y = size
p = pro
}
}
func theRoutine(n: Int) {
prog.hidden = false
prog.doubleValue = 0
prog.maxValue = 7 * 40
let priority = DISPATCH_QUEUE_PRIORITY_HIGH
dispatch_async(dispatch_get_global_queue(priority, 0)) {
self.theFunc(n, var1: 0.06, var2: 0.06, var3: 7)
self.theFunc(n, var1: 0.1*log(Double(n))/Double(n), var2: 0.3*log(Double(n))/Double(n), var3: 7)
dispatch_async(dispatch_get_main_queue()) {
self.prog.hidden = true
self.appOut("done!")
}
}
}
//This doesn't
// func theFunc(n: Int, var1: Double, var2: Double, var3: Int) {
// var m: AnEnum
// var gra: SomeClass
// var p = var1
// for _ in 0...(var3 - 1) {
// var str = "blah \(p)\n"
// for _ in 1...20 {
// gra = SomeClass(size: n, pro: p)!
// m = self.doSomething(gra)
// switch m {
// case .First(let dat):
// str = str + "Blah:\n\(self.arrayF(dat, transform: {"blah\($0)blah\($1)=blah"}))" + "\n\n" + str
// case .Second(let odat):
// str = str + "Blah\(odat.count) blah\(self.arrayF(odat, transform: {"bl\($1)"}))" + "\n\n" + str
// }
// dispatch_async(dispatch_get_main_queue()) {
// self.prog.incrementBy(1)
// }
// }
// dispatch_async(dispatch_get_main_queue()) {
// // update some UI
// self.display.string = str + "\n" + (self.display.string ?? "")
// }
// p += var2
// }
// }
//This works
func theFunc(n: Int, var1: Double, var2: Double, var3: Int) {
var m: AnEnum
var gra: SomeClass
var p = var1
for _ in 0...(var3 - 1) {
var str = "blah \(p)\n"
for _ in 1...20 {
gra = SomeClass(size: n, pro: p)!
m = self.doSomething(gra)
switch m {
case .First(let dat):
str = "Blah:\n\(self.arrayF(dat, transform: {"blah\($0)blah\($1)=blah"}))" + "\n\n" + str
case .Second(let odat):
str = "Blah\(odat.count) blah\(self.arrayF(odat, transform: {"bl\($1)"}))" + "\n\n" + str
}
dispatch_async(dispatch_get_main_queue()) {
self.prog.incrementBy(1)
}
}
dispatch_async(dispatch_get_main_queue()) {
// update some UI
self.display.string = str + "\n" + (self.display.string ?? "")
}
p += var2
}
}
func doSomething(G: SomeClass) -> AnEnum {
usleep(30000)
if drand48() <= G.p {
return AnEnum.First([0, 0])
} else {
return AnEnum.Second([1, 1, 1])
}
}
enum AnEnum {
case First([Int])
case Second([Int])
}
func appOut(out: String?) {
if out != nil {
display.string = out! + "\n\n" + (display.string ?? "")
}
}
func arrayF(array: [Int], transform: (index: Int, value: Int) -> String) -> String {
let arr = Array(0...(array.count - 1))
return "[\(arr.map{transform(index: $0, value: array[$0])}.joinWithSeparator(", "))]"
}
}
str
。我相信这就是您的问题所在,直到您知道str
已经完成,才不要调度self.display.string = str + "\n" + (self.display.string ?? "")
。这就是Objective C中原子操作的方便之处。 - Knight0fDragonstr = str +“Blah \(odat.count)”
视为str + =“Blah \(odat.count)”
。在后者中,str
是一个被操作改变(但具有复制行为...)的inout
变量,与使用+
运算符有一些微妙的差别,后者使用运算符调用的返回值来覆盖/改变str
。声称str
为inout变量对str
的竞争条件可能有一些影响。 - dfrib