我在确定存在变量方面遇到了一些麻烦.

因为这里的Animal总是符合Hashable,我可以想象any Animal也会符合have.

然而,我看到的错误让我产生了另一种 idea .有人能帮我解释一下为什么会发生这种情况吗?如果可能的话,帮我解决这个问题?

import SwiftUI
import PlaygroundSupport

protocol Animal: Hashable {
    var name: String { get }
}

struct Cow: Animal {
    let name: String
}

struct Chicken: Animal {
    let name: String
}

let anAnimalList: [any Animal] = [Cow(name: "Aaron"), Chicken(name: "Billy"), Cow(name: "Charlie"), Chicken(name: "Delilah")]

struct myView: View {
    @State private var anAnimal: (any Animal)?
    
    var body: some View {
        VStack {
            List(anAnimalList, id: \.self, selection: $anAnimal) { animal in // ERROR: Type 'any Animal' cannot conform to 'Hashable'
                Text("Animal")
            }
            
            Text("Animal is \(anAnimal?.name ?? "Null")")
        }
    }
}

PlaygroundPage.current.setLiveView(myView())

推荐答案

假设我们想找到一种方法来列出[any Animal]个,而不是"为什么会发生这样的事情":(请参阅相应的WWDC22会话以找到第二个问题的答案)

使用Xcode 14b3/iOS 16测试

demo

让我们跳进这个洞...

原始代码中有两处报告的错误:

List(anAnimalList, 
                   id: \.self,     // << 1st place
            selection: $anAnimal   // << 2nd place
) { animal in
    Text("Animal")
}

1st place-因为Animal是不可识别的,self和具体类型的实例有关,所以我们不应该使用\.self(因为编译器无法推断具体类型),而是直接通过\.id识别

第一个问题有一个可能的解决方案:

protocol Animal: Hashable, Identifiable {
    var id: UUID { get }
    var name: String { get }
}

struct Cow: Animal {
    let id = UUID()
    let name: String
}

struct Chicken: Animal {
    let id = UUID()
    let name: String
}

    var body: some View {
        VStack {
            List(anAnimalList, id: \.id) { animal in   // << no error !!
                Text("Animal: \(animal.name)")
            }
        }
    }

2nd place-关于 Select ;故事是一样的,Swift 应该知道" Select 的具体类型"或能够"从代码中推断",这两者在编译类型上都是不可能的,所以与其试图用头撞墙,不如找一扇门...

一个可能的解决方案是使用在上下文中已知和具体的内容进行 Select ...我们刚刚在"id"上面添加了它

这是对第二部分的修正

@State private var anAnimalID: UUID? // << here !!

var body: some View {
    VStack {
        List(anAnimalList, id: \.id, selection: $anAnimalID) { animal in
            Text("Animal: \(animal.name)")
        }
        if let animal = anAnimalList.first { $0.id == anAnimalID } {
            Text("Animal is \(animal.name)")
        }
    }
}

Test code on GitHub

Ios相关问答推荐

什么是最好的方式使用DateFormatters在可扩展视图cellForRowAt方法

不使用iOS 17修改器修改SWIFT用户界面视图

通过拖动更改视图位置的SwiftUI会引发UI错误

GraphQL iOS Apollo客户端自动持久化查询导致崩溃

Swift locationManager.requestWhenInUseAuthorization() 不提示用户

SwiftUI 中的描边图像边框

工具栏底部 iOS 16 - SwiftUI

List touch Tabbar 时 SwiftUI Tabbar 消失

弹出视图后使所有背景 UI 模糊

从远程通知启动时,iOS 应用程序加载错误

使用swift将图像转换为A4大小的pdf

如何 comments .plist 文件中的行?

iOS 中是否有用于自定义振动的 API?

没有 Mac 的 Xamarin Visual Studio IOS 开发?

是否可以使用 sharedHTTPCookieStorage 为 UIWebView 手动设置 cookie?

Xcode 8:函数类型不能有参数标签 destruct 我的构建

iOS 应用程序中的手动语言 Select (iPhone 和 iPad)

如何使用 Contacts Framework 获取 iOS 9 中的所有联系人记录

UITextView 从文本的底部或中间开始

如何在 UILabel 中找到文本子字符串的 CGRect?