更新数组内结构中的属性

时间:2016-06-07 15:30:43

标签: ios arrays swift struct

在我的应用中,我下载了一大堆JSON。

然后我将其存储为结构数组,并使用它来填充UITableView

结构的一个属性是图像的NSURL。另一个属性是可选的UIImage

该struct有一个变异函数downloadImage,它使用URL下载图像并将其存储在其属性中。

喜欢这个......

struct SearchItem {
    // other properties...
    let iconURL: NSURL
    var icon: UIImage?

    mutating func downloadImage() -> Task<UIImage> {
        let tsc = TaskCompletionSource<UIImage>()

        NSURLSession.sharedSession().downloadTaskWithURL(iconURL) {
            (location, response, error) in
            if let location = location,
                data = NSData(contentsOfURL: location),
                image = UIImage(data: data) {
                self.icon = image
                tsc.setResult(image)
                return
            }

            tsc.setError(NSError(domain: "", code: 1, userInfo: nil))
        }.resume()

        return tsc.task
    }
}

我遇到的问题是这个。 (我过去一直对此感到难过。)

我有一个数组[SearchItem],用于填充tableview。

cellForRow我有代码...... if let searchItem = items[indexPath.row]...

然后检查图像是否为零并下载...

if let image = searchItem.icon {
    cell.imageView.image = image
} else {
    searchItem.downloadImage().continueOnSuccessWith(Executor.MainThread) {
        _ in
        tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .None)
    }
}

但是这永远不会将图像放入细胞中。这是因为SearchItem是结构,所以pass-by-value。因此,我下载图像的搜索项与存储在数组中的SearchItem不同。

如何确保将下载的图像存储到实际数组中的SearchItem

2 个答案:

答案 0 :(得分:4)

使用课程。

您在searchItem方法中获得了cellForRow的副本。无论你做什么,都只会对那份副本进行。您真正想要的是您对该副本所做的更改将应用​​于阵列中的版本。

因此,您需要引用语义,因此请使用类。

如果你喜欢的话,你可以跳过将更新后的副本重新插入到原始数组中,但除了一系列额外的代码和其他一些问题之外,它还能带给你什么。

答案 1 :(得分:3)

结构是轻量级数据对象,不通过引用传递,而是在a)将其传递给新函数时根据需要复制自身,b)尝试在块中访问它。 Swift中的数组与Obj-C对应的工作方式略有不同。如果您有一个类对象Array,那么该数组将是一个引用类型,您将能够实现您在此处尝试实现的目标。但另一方面,如果Array是Structs,则数组会丢失其引用语义并使用copy-by-value。

如果使用得当,这种差异非常强大,您可以大大优化代码,使其运行更快,可变对象引用产生的错误更少,代码的多个部分发生变化等等。但是它作为开发人员,您可以了解这些优化的好处在哪里有用,或者在哪里使用对象更有意义。