当前位置: 首页 > 面试题库 >

异步回调中的Inout参数无法按预期工作

葛承嗣
2023-03-14
问题内容

我正在尝试插入带有inout参数的函数,以将从异步回调接收的数据追加到外部数组。但是,它不起作用。我尽一切所能找出原因-没运气。

正如@AirspeedVelocity所建议的那样,我将代码重写如下,以删除不必要的依赖项。我还使用an Int作为inout参数来保持简单。
输出始终为:
c before: 0
c after: 1

我无法弄清楚这里出了什么问题。

func getUsers() {
    let u = ["bane", "LiweiZ", "rdtsc", "ssivark", "sparkzilla", "Wogef"]
    var a = UserData()
    a.userIds = u
    a.dataProcessor()
}

struct UserData {
    var userIds = [String]()
    var counter = 0
    mutating func dataProcessor() -> () {
        println("counter: \(counter)")
        for uId in userIds {
            getOneUserApiData(uriBase + "user/" + uId + ".json", &counter)
        }
    }
}

func getOneUserApiData(path: String, inout c: Int) {
    var req = NSURLRequest(URL: NSURL(string: path)!)
    var config = NSURLSessionConfiguration.ephemeralSessionConfiguration()
    var session = NSURLSession(configuration: config)
    var task = session.dataTaskWithRequest(req) {
        (data: NSData!, res: NSURLResponse!, err: NSError!) in
        println("c before: \(c)")
        c++++
        println("c after: \(c)")
        println("thread on: \(NSThread.currentThread())")
    }

    task.resume()
}

谢谢。


问题答案:

可悲的是,修改inout在异步回调参数是没有意义的。

从官方文件:

参数可以提供默认值以简化函数调用,并且可以作为输入-输出参数传递,参数 在函数完成执行后会 修改传递的变量。

输入输出参数具有一个值,该值传递给函数,由函数修改,然后从函数 传递回 以替换原始值。

语义上,输入输出参数不是“按引用调用”,而是“按复制副本恢复”。

就您而言,counter仅在getOneUserApiData()返回时才回写,而不在dataTaskWithRequest()回调中。

这是您的代码中发生的事情

  1. getOneUserApiData()调用时,将值counter 0复制到c1
  2. 闭合捕获c1
  3. 呼叫 dataTaskWithRequest()
  4. getOneUserApiData返回,并且-未经修改c-1的值被写回到counter
  5. 重复1-4步骤为c2,c3,c4 …
  6. …从互联网上获取…
  7. 回调被调用,并且c1递增。
  8. 回调被调用,并且c2递增。
  9. 回调被调用,并且c3递增。
  10. 回调被调用,并且c4递增。

结果counter是未修改的:(

详细说明

通常,in-out参数是通过引用传递的,但这只是编译器优化的结果。当闭包捕获inout参数时,“传递引用”是 不安全的
,因为编译器无法保证原始值的生存期。例如,考虑以下代码:

func foo() -> () -> Void {
    var i = 0
    return bar(&i)
}

func bar(inout x:Int) -> () -> Void {
    return {
        x++
        return
    }
}

let closure = foo()
closure()

在此代码中,返回var ifoo()将其释放。如果x是对的引用ix++则会导致访问冲突。为了防止出现这种竞争情况,Swift在此处采用了“按副本还原呼叫”策略。



 类似资料:
  • 问题内容: 建立: 我正在做一个ajax-jsonp调用,它工作正常。此的回调函数更改变量“ myVaraible”的值。在调用之后,有一些if-else逻辑对“ myVaraible”的值起作用。 这是代码: 问题: Ajax调用保持“待处理”状态,控制移至if- else块(有效执行myVariable的旧/陈旧值)。然后,ajax调用完成。简而言之,在两个方框中,先执行然后执行 如您所见,我

  • 在我的flatter应用程序中,我试图在异步函数完成后使用whenComplete()方法运行一些代码。问题是whenComplete()方法中的代码甚至在异步函数完成之前就被执行了。 我也尝试过使用then()方法,这也产生了相同的结果。 这是我在其中调用异步函数的init函数: 这是异步函数的函数体: 运行应用程序时的控制台输出为: 因此,在调用异步函数getUserHomes的init()函

  • 问题内容: 我正在使用selenium来抓取一些数据。 我单击的页面上有一个按钮,说“ custom_cols”。此按钮为我打开一个窗口,从中可以选择列。 此新窗口有时需要一些时间才能打开(大约5秒钟)。所以我已经使用了 延迟为20秒。但是有时它无法在新窗口中选择查找元素,即使该元素可见。在其余时间中,这种情况仅发生十次一次。 我在其他地方也使用了相同的功能(WebDriverWait),并且可以

  • 问题内容: 经过测试后,我只能对已经解析过的JSON数据返回一个肯定值。 根据官方文件: isValidJSONObject返回一个布尔值,该布尔值指示是否可以将给定对象转换为JSON数据。 但是,尽管事实是我尝试将其从JSON转换为NSDictionary的对象都可以正常转换,但仍会返回。 这是我的代码: 我的日志包含以下内容: 然后是dict的输出,这是一个巨大的NSMutableDictio

  • 问题内容: 考虑以下可以在任何程序执行之前预加载的库: 问题是,尽管总是调用全局变量的构造函数,但对于某些程序却不调用析构函数,例如: 对于其他一些程序,按预期方式调用析构函数: 您能解释一下为什么在第一种情况下不调用析构函数吗?编辑:上面的问题已得到解答,即程序可能会使用_exit(),abort()退出。 然而: 有没有办法在预加载的程序退出时强制调用给定函数? 问题答案: 具有作为其初始化代

  • 我必须将日期-时间字符串转换为分区日期-时间对象。我使用DateTimeForman读取模式。根据留档,模式中的“Z”可以接受以下格式: /-0000 但是“分区约会”。parse(myDate,formatter)只适用于第一种情况;相反,在第二种情况下,代码生成一个异常。 我用的是8Java 我做错什么了?谢谢!