Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

swiftにおけるcomputedのやり方

解決したいこと

Swiftでcomputedに当たる操作をどうやって実現するか

内容

データをフィルタリングしてグループ分けしたいです。
(例として用いているデータは、鬼滅の刃でキャラクターが最後に生きていたかでグループわけしています)

javascriptとvueでいうと、以下のような感じです。

//もとのデータ
const Hashiras = [
  {name:"Tomioka",bless:"mizu", alive:true},
  {name:"Kanroji",bless:"koi", alive:false},
  {name:"Himejimma",bless:"iwa", alive:false},
  {name:"Shinazugawa",bless:"kaze", alive:true}
]

//加工後
const Survivors = [
  {alive:true, characters:[{name:"Tomioka",bless:"mizu"},{name:"Shinazugawa",bless:"kaze"}]},
  {alive:false,characters:[{name:"Kanroji",bless:"koi"},{name:"Himejima",bless:"iwa"}]}
]
//vueならこんな感じ

data():return {
  hashiras = [
    {name:"Tomioka",bless:"mizu", alive:true},
    {name:"Kanroji",bless:"koi", alive:false},
    {name:"Himejimma",bless:"iwa", alive:false},
    {name:"Shinazugawa",bless:"kaze", alive:true}
  ]
},
computed:{
  survivors(){
    const alives = this.hashiras.filter(hashira=>hashira.alive)
    const deathes = this.hashiras.filter(hashira=>!hashira.alive)
    return [
      {alive:true,characters:alives},
      {alive:false,characters:deathes}
    ]
  } 
}

//flatMapを用いればもっと上手くできそうですが、ひとまずfilterで実装してます。

これをSwiftUIでやろうとして、やり方がわからなくて困っています。

struct Hashira:Identifiable {
    var id: Int
    let name: String
    let image: Image
    let alive: Bool
}

struct Survivor:Identifiable{
    var id:Int
    let alive:Bool
    let characters:Any
}

struct ContentView: View {

    let hashiras: [Hashira] = [
        .init(id:0, name: "kanroji", image:Image("kanroji"),alive: false),
        .init(id:1, name: "himejima", image:Image("himejima"),alive: false),
        .init(id:2, name: "iguro", image:Image("iguro"),alive: false),
        .init(id:3, name: "tomioka", image: Image("tomioka"),alive: true)
    ]

    let survivors:[Survivor]=[
        .init(id:0, alive: true, characters: hashiras.filter{ $0["alive"]}),
        .init(id:1, alive: false, characters: hashiras.filter{ !$0["alive"]})
    ]

・・・以下略

発生している問題・エラー

上記の状態では、以下のようなエラーメッセージが出ます。

Cannot use instance member 'hashiras' within property initializer; property initializers run before 'self' is available

Value of type 'Hashira' has no subscripts

selfをつけましたが、今度は以下のようなメッセージになります。

    let survivors:[Survivor]=[
        .init(id:0, alive: true, characters: self.hashiras.filter{ $0["alive"]}),
        .init(id:1, alive: false, characters: self.hashiras.filter{ !$0["alive"]})
    ]
Cannot find 'self' in scope

全体的にXcodeはエラーメッセージが何言ってるのかよくわからなくて、ググっても解決記事が見当たらなくて困ります。

よろしくお願いします。

0

2Answer

ensan_hcl様

まさに私が理解していなかったところを解説してくださいまして、ありがとうございます。
最後に思いついていなかった書き方まで書いてくださり、非常に参考になりました。

Swiftはまだ情報が少なく、チュートリアルから外れたことをしようとすると行き詰まることが多いですが、諦めずに勉強します。

1Like

エラーの原因は2点です。

    let survivors: [Survivor]=[
        .init(id:0, alive: true, characters: self.hashiras.filter{ $0["alive"]}),
        .init(id:1, alive: false, characters: self.hashiras.filter{ !$0["alive"]})
    ]

まず、プロパティへのアクセスはhashira["alive"]ではなくhashira.aliveという形で行います。[]を用いてアクセスする記法にはsubscriptという名前がついており、Hashiraにはそのようなsubscriptが定義されていないので「Value of type 'Hashira' has no subscripts」というエラーになっています。

次に、Swiftではinitが実行された後でないとselfを用いることができません。この場合survivorsはinitが実行される前に評価されてしまうので、エラーになります。

Vueでのcomputedに当たるものかは分かりませんが、Swiftで「Computed property」と呼ばれるものなら次のように書けます。これはプロパティの定義でgetterのみを書いたものと同じで、アクスのたびに計算が行われます。

    var survivors: [Survivor] {
        [
        .init(id:0, alive: true, characters: self.hashiras.filter{ $0.alive}),
        .init(id:1, alive: false, characters: self.hashiras.filter{ $0.alive})
        ]
    }

最初に一度計算してそれきりで良いのであれば、次のような方法でもいいかもしれません。

    let hashiras: [Hashira]
    let survivors: [Survivor]

    init(){
        let hashiralist: [Hashira] = [......] //hashirasの値をここに書く
        self.hashiras = hashiralist
        self.survivors = [
            .init(id:0, alive: true, characters: self.hashiras.filter{ $0.alive}),
            .init(id:1, alive: false, characters: self.hashiras.filter{ $0.alive})
        ]
    }

鬼滅の最終巻未読のため、コードをちゃんと読まずに答えています。間違っていたらすみません・・・。

0Like

Your answer might help someone💌