【 Swift 】2次元配列と1次元配列の相互変換 🤔

こんな12年前の so の書き込み。


p.x = index / 3;
p.y = index % 3;

👉 c# - Convert 1D array index to 2D array index - Stack Overflow hatena-bookmark

さすが、先人先生。

やってみました。

長ったらしいですが考え方を思い出したいときのために。

 

🤔 配列をn個ずつに分割する

副産物としてこんなかんじに書けました。


extension Array {
  func chunked(by: Int) -> [[Element]] {
    return  (0 ..< (self.count / by)).map {
      Array(self[$0 * by ..< ($0 + 1) * by])
    }
  }
}

print(
  [1, 2, 3, 4, 5, 6].chunked(by: 3)
)
// [[1, 2, 3], [4, 5, 6]]

 

🤔 まとめ

配列の変換


let d2: [[String]] = [
  ["あ", "い", "う", "え", "お"],
  ["か", "き", "く", "け", "こ"],
  ["さ", "し", "す", "せ", "そ"]
]

// 2次元から1次元 *
let d1 = d2.flatMap { $0 }
print(d1)
// ["あ", "い", "う", "え", "お", "か", "き", "く", "け", "こ", "さ", "し", "す", "せ", "そ"]

print(
  // 1次元から2次元 *
  (0 ..< d1.count / numCols).map {
    Array(d1[($0 * numCols) ..< ($0 + 1) * numCols])
  }
)
// [["あ", "い", "う", "え", "お"], ["か", "き", "く", "け", "こ"], ["さ", "し", "す", "せ", "そ"]]

extension 化する。


extension Array where Element: Collection { 
  func toD1() -> [Element.Element] { // nested
    return self.flatMap { $0 } 
  }
}

extension Array {
  func toD2(numCols: Int) -> [[Element]] {
    return (0 ..< self.count / numCols).map {
      Array(self[($0 * numCols) ..< ($0 + 1) * numCols])
    }
  }
}

1次元配列インデックスと2次元配列座標の関係


index = y * numCols + x

x = index % numCols
y = index / numCols

SwiftData の inMemory で実装してみたが遅かったので、@Observable クラスへ。

👉 【 SwiftUI 】 Pong Wars を SwiftUI に移植してみた hatena-bookmark

しかし、正直、勉強すればするほど謎が増えます !


👉 【Swift】2次元配列 で 転置行列 ( transpose matrix ) hatena-bookmark




【SwiftUI】 親から隠そうとすると怒られる 子View ローカルプロパティの記述

分かったつもりでいたが、

一発で書けない。

隠そうとすると怒られる。


struct ChildView: View {

  // var count = 0 // OK
  private var count = 0 // 'ParentView' initializer is inaccessible due to 'private' protection level

  var body: some View {

試してみる。


struct ChildView: View {

  // public var count = 0 // OK
  // internal var count = 0 // OK
  // private var count = 0 // NG

  // @State var count = 0 // OK
  // @State public var count = 0 // OK
  // @State internal var count = 0 // OK
  // @State private var count = 0 // OK

  var body: some View {

なんでなの?

「@State でない可変プロパティを書くな。」

ってこと ?

記述時の考え方の順番を明確にしておきたい。

この自動コンストラクタ生成的な memberwise initializer ての便利だけど馴染みづらくない ?

👉 【Swift】「public」 を省略しない理由 🚫 hatena-bookmark
👉 【SwiftUI】View プロパティの記述 hatena-bookmark


Xcode の自動ビルドのせいで編集できないのだが - How to disable Automatically Refresh Canvas and background build compile

Xcode の自動ビルドというかコンパイルというか。

手動にしたいんですけど。

自動で裏でなんかしら動いて、

エディターを触るのに詰まる感じ。

ロジックをいじるときには非常にストレス。

 

😩 Settings → General → Show live issues OFF

良くわからない。

ON でも OFFでも何がどう変わるのか。

ググるとやたらヒットする。

👉 xcode 9 how to disable auto build … | Apple Developer Forums hatena-bookmark

 

😩 Editor → Canvas → Automatically Refresh Canvas OFF

You can turn off the auto-compile feature for previews/canvas'. When having a SwiftUI View open in the editor go to the Editor -> Canvas -> Automatically Refresh Canvas.

👉 Stop auto compile on Xcode preview - Stack Overflow hatena-bookmark

欲しかったのはこれかな?

ファイルを編集すると、Canvas 上に


「Preview paused 🔃」

と表示される。

🔃 を押さないと、自動でビルドは行われない。

これだわ !

 

😩 まとめ

Xcode が裏で動いてコード編集できないときは、


Editor

  ↓

Canvas 

  ↓

Automatically Refresh Canvas OFF

です。

リフレッシュするときのショートカットは、


⌥ (Option) + ⌘ (Command) + P

のようですです。

しかし、そもそも、

編集操作を妨げてまで

デフォルトで自動でリフレッシュする必要なくね?

初心者はつらい。いちいち詰まる。


【 SwiftUI 】 Pong Wars を SwiftUI に移植してみた

見てて飽きないので Xcode Playground で SwiftUI の練習。

ソースは以下2つあればいけるだろう、と雰囲気で。

👉 vnglst/pong-wars hatena-bookmark
👉 vocdex/pong-wars-python: Python version of Pong Wars with Pygame hatena-bookmark

一つのファイルで終わらせたい。

 

🏓 結果




 

🏓 まとめ

Playground では遅すぎですがソースコード。

テストプロジェクトなどで Preview や Simulator でみると、

まあ、スピードもそれなりで上の動画の雰囲気でした。

Gist のコードはあれこれ更新されていきます。いってます。

どうぞよろしくお願います。

 

🏓 追記

4100ループ付近で。

残念 !

計算と描画ははっきり区別しないと痛い目に遭いそうな感じ。

→ 修正しました。

→ 2024-02-07 衝突時のロジックを確認、更新しました。


【SwiftUI】 iOS / macOS の レイアウト記述を typealias で切り替える

よくある入力欄を iOS で作ります。


// iOS

Form {
  Section(header: Text("Name of Living Accommodation")) {
    Group {
      TextField("Enter place name here…", text: $placeName)
    }
  }
  Section(header: Text("Address of Living Accommodation")) {
    Group {
      TextField("Enter address here…", text: $address)
    }
  }
}

いい感じです。

👉 Form | Apple Developer Documentation hatena-bookmark
👉 Group | Apple Developer Documentation hatena-bookmark

macOS に切り替えてみます。

なんか気持ちが悪いです。

以下のようにレイアウト記述を書き換えます。


 iOS   | macOS
-------+----------
 Form  → List
 Group → GroupBox


// macOS

List { // *
  Section(header: Text("Name of Living Accommodation")) {
    GroupBox { // *
      TextField("Enter place name here…", text: $placeName)
    }
  }
  Section(header: Text("Address of Living Accommodation")) {
    GroupBox { // *
      TextField("Enter address here…", text: $address)
    }
  }
}

いい感じになりました。

👉 List | Apple Developer Documentation hatena-bookmark
👉 GroupBox | Apple Developer Documentation hatena-bookmark

自動で切り替えるようにしておきます。


// iOS and macOS

#if os(iOS)

Form {
  Section(header: Text("Name of Living Accommodation")) {
    Group {
      TextField("Enter place name here…", text: $placeName)
    }
  }
  Section(header: Text("Address of Living Accommodation")) {
    Group {
      TextField("Enter address here…", text: $address)
    }
  }
}

#else

List { 
  Section(header: Text("Name of Living Accommodation")) {
    GroupBox { 
      TextField("Enter place name here…", text: $placeName)
    }
  }
  Section(header: Text("Address of Living Accommodation")) {
    GroupBox { 
      TextField("Enter address here…", text: $address)
    }
  }
}

#endif

長ったらしいですね。

たった3か所の置き換えだけなのに。

■ typealias を使う

レイアウト記述の同名のエイリアスを作ってそれらを OS で切り分けます。


// iOS and macOS

#if os(iOS)
typealias TripForm = Form
typealias TripGroupBox = Group
#else
typealias TripForm = List
typealias TripGroupBox = GroupBox
#endif


 typealias    | iOS   | macOS
--------------+-------+----------
 TripForm     | Form  | List
 TripGroupBox | Group | GroupBox

それらエイリアスを使って本体は記述する。


// iOS and macOS

TripForm { // *
  Section(header: Text("Name of Living Accommodation")) {
    TripGroupBox { // *
      TextField("Enter place name here…", text: $placeName)
    }
  }
  Section(header: Text("Address of Living Accommodation")) {
    TripGroupBox { // *
      TextField("Enter address here…", text: $address)
    }
  }
}

これできれいに切り替えできました !

typealias を切り替えることで、

本体コードの挙動を置き換えてます。

さすが、Apple 公式サンプルコードは勉強になります。


Trip/Trips-SwiftData/Trips/EditLivingAccommodationsView.swift
Trip/Trips-SwiftData/Trips/SwiftUIHelper.swift

以下、Apple ページ「Download」からどうぞ。


👉 Adopting SwiftData for a Core Data app | Apple Developer Documentation hatena-bookmark