无法分配 _ArrayProtocol 中的项目

Can't assign the item in _ArrayProtocol

您好,我正在尝试使用 ParseLiveQuery

检索数据

我的问题是...我无法分配数组中的项目...

import Foundation
import Parse
import ParseLiveQuery

extension _ArrayProtocol where Iterator.Element == PFObject {
    mutating func updateWithEvent(event: Event<PFObject>) {
        switch event {
        case .created(let object):
                append(object)
        case .entered(let object):
                append(object)
        case .deleted(let object):
            if let index = index(of: object) {
                remove(at: index)
            }
        case .left(let object):
            if let index = index(of: object) {
                remove(at: index)
            }
        case .updated(let object):
            if let index = index(of: object) {
                //I got an error : Cannot assign through subscript: subscript is get-only
                self[index] = object

            }
        }
    }
}

问题来了

 case .updated(let object):
                if let index = index(of: object) {
                    //I got an error : Cannot assign through subscript: subscript is get-only
                    self[index] = object

                }
            }

有人知道吗?

首先,您应该小心处理内部类型和协议。协议名称前的下划线 (_ArrayProtocol) 告诉我们这一点;这是一个内部协议,这意味着它可能会在未来的 Swift 更新中提示更改而不会发出警告(因为使用 Swift 的开发人员不应依赖 direct/explicit 对内部协议的使用)。

internal protocol _ArrayProtocol: RangeReplaceableCollection, ...

来自 swift/stdlib/public/core/ArrayType.swift.


现在,至于你的错误,错误信息很清楚

Cannot assign through subscript: subscript is get-only

即,_ArrayProtocolsubscript 没有可用的 setter(例如,通过默认实现:因为您在扩展中使用 _ArrayProtocol 作为类型本身).它确实有 setter 用于 subscript 蓝图,但不存在它的默认实现,而 getter 的默认实现可从 RangeReplaceableCollection.

获得

因此对于这种特殊情况,如果您想在 index 处替换 selfElement,您可以例如利用符合 _ArrayProtocol 的类型可访问的变异 replaceSubRange(_:, with:) method of RangeReplaceableCollection,因为协议本身符合 RangeReplaceableCollection:

replaceSubrange(index...index, with: [object])

如果我们暂时离开直接使用内部协议不合适的主题,我们可以构建一个实施此修复的示例,一个可以实际验证的示例(与您已经验证过的示例相反)在您的问题中提供...)。

enum Foo {
    case created(Int)
    case entered(Int)
    case deleted(Int)
    case left(Int)
    case updated(Int)
}

// do not work directly with this _internal_ protocol!!
extension _ArrayProtocol where Iterator.Element == Int {
    mutating func updateWithEvent(event: Foo) {
        switch event {
        case .created(let object):
            append(object)
        case .entered(let object):
            append(object)
        case .deleted(let object):
            if let index = index(of: object) {
                remove(at: index)
            }
        case .left(let object):
            if let index = index(of: object) {
                remove(at: index)
            }
        case .updated(let object):
            if let index = index(of: object) {  
                replaceSubrange(index...index, with: [object])
            }
        }
    }
}

但话又说回来,您不应该对内部协议实施这样的扩展。考虑改为实现 public type/protocol 的扩展,例如作为 Array 的扩展,限制为 Element 符合 Equatable:

enum Foo<T> {
    case created(T)
    case entered(T)
    case deleted(T)
    case left(T)
    case updated(T)
}

extension Array where Element: Equatable {
    mutating func updateWithEvent(event: Foo<Element>) {
        switch event {
        case .created(let object):
            append(object)
        case .entered(let object):
            append(object)
        case .deleted(let object):
            if let index = index(of: object) {
                remove(at: index)
            }
        case .left(let object):
            if let index = index(of: object) {
                remove(at: index)
            }
        case .updated(let object):
            if let index = index(of: object) {
                self[index] = object
            }
        }
    }
}

请注意,与使用内部 _ArrayProtocol 的具体类型(如在您自己的扩展中,self 的用法)相比,后者没有可用的 setter subscriptArray,另一方面,does,这意味着当扩展应用于 Array.[= 时,您可以应用原始简单元素替换 self[index] = object 43=]