20200720のSwiftに関する記事は5件です。

Swift日記(8日目)

今日やったこと

  • 用語の勉強

FizzBuzzやった

FizzBuzz.swift
import UIKit
func printfizzbuzz(fizz_value:Int){
    for i in 1...fizz_value{
        if i % 15 == 0 {
            print("FizzBuzz")
        }else if i % 3 == 0  {
            print("Fizz")
        }else if i % 5 == 0 {
            print("Buzz")
        }else{
            print(i)
        }
    }
}

printfizzbuzz(fizz_value: 100)

クラス・関数・変数

  • 関数
    • 実行する命令のかたまり、のようなもの。中でいろんな処理をしてくれる
  • 変数
    • 様々なものを入れておく入れ物。中身を一定のルールで変えることができる。中身を変えることができない入れ物を定数という。
  • クラス
    • 関数と変数をまとめた集まり。
    • クラスの中にある変数をプロパティ、関数をメソッドと呼ぶ。なぜぇ。。。
    • クラスの中でプロパティやメソッドが働いてできあがった変数をインスタンスという。

変数一個に2種類も呼び方あるの納得いかねぇ。。。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Swift】可変長引数の関数に配列を渡したい!ときのworkaround

結論

自前の関数なら同名の関数をoverloadできます。

 // 配列を引数に取る関数側にロジックを実装する
 func greet(_ people: [String]) {
     print("Hello, \(people.joined(separator: ", "))!")
 }

 // 可変長引数を持つ関数側では、内部で配列を引数に取る関数を呼び出す
 func greet(_ people: String...) {
     greet(people)
 }

言語仕様として、引数に渡すときに配列を展開することはできないので、フレームワーク内の可変長引数(例えば、printなど)の関数に配列を渡すのは現状は難しいようです。

参考

Passing an array to a function with variable number of args in Swift

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Swift】\()を使用せず、文字列と一緒に変数をコンソール出力する方法

コンソールに文字列と一緒に変数を出力したい際、下記のように「 \ (変数)」を使用する方が多いと思います。

var foodList = ["カレー", "ラーメン", "カツ丼"]
print("食べ物: \(foodList)")
//出力結果 食べ物: ["カレー", "ラーメン", "カツ丼"]

実は下記のように、変数の前に「 , 」をつけるだけでもOKなんです。
「 \ ()」をタイプするよりも圧倒的に楽なのでオススメです。

print("食べ物: ", foodList)
//出力結果 食べ物: ["カレー", "ラーメン", "カツ丼"]
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ディクショナリからタプルの配列を作成する

はじめに

  • Swift には、連想配列的なデータ構造としてディクショナリがあります
  • ディクショナリはデータの順序を保証しないので、そのままではテーブルビューやコレクションビューのデータソースとして利用しにくいです
  • その場合は、タプルの配列に変換すると上手く行きます

検証環境

  • Xcode 11.5
  • Swift 5.2

利用する機能

sorted(by:)

  • ディクショナリのメソッド
  • 引数に渡した関数 by がソート条件
    • 関数 by の引数
      • 2 つのタプル(それぞれディクショナリの n 番目の要素と n + 1 番目の要素に対応)
    • 関数 by の戻り値
      • Boolfalse なら並び替え)
  • 戻り値は [(key: ディクショナリの key の型, value: ディクショナリの value の型)]
    • つまり、ディクショナリとほぼ同じ構造を持った「タプルの配列」

コード例

  • 以下はディクショナリ [String: Int] からタプルの配列 [(key: String, value: Int)] に変換する例です
SortedDictionary.playground
import Foundation

var scores: [String: Int] = [
    "Steve Yamada": 34,
    "Jeff Takeshita": 87,
    "Mickey Yoshida": 100,
    "Charly Kinoshita": 53,
    "Anna Saito": 19,
    "Robert Suzuki": 97,
    "Erick Kawakami": 32,
    "John Miyabe": 64,
    "Gregory Goto": 76
]

print("""

    Ascending by key
    ========================
    """)
var sortedByNameAsc: [(key: String, value: Int)] = scores.sorted { $0.key < $1.key }
sortedByNameAsc.forEach { print("\($0.key): \($0.value)") }

print("""

    Descending by key
    ========================
    """)
var sortedByNameDesc: [(key: String, value: Int)] = scores.sorted { $0.key > $1.key }
sortedByNameDesc.forEach { print("\($0.key): \($0.value)") }

print("""

    Ascending by value
    ========================
    """)
var sortedByScoreAsc: [(key: String, value: Int)] = scores.sorted { $0.value < $1.value }
sortedByScoreAsc.forEach { print("\($0.value): \($0.key)") }

print("""

    Descending by value
    ========================
    """)
var sortedByScoreDesc: [(key: String, value: Int)] = scores.sorted { $0.value > $1.value }
sortedByScoreDesc.forEach { print("\($0.value): \($0.key)") }
出力結果
Ascending by key
========================
Anna Saito: 19
Charly Kinoshita: 53
Erick Kawakami: 32
Gregory Goto: 76
Jeff Takeshita: 87
John Miyabe: 64
Mickey Yoshida: 100
Robert Suzuki: 97
Steve Yamada: 34

Descending by key
========================
Steve Yamada: 34
Robert Suzuki: 97
Mickey Yoshida: 100
John Miyabe: 64
Jeff Takeshita: 87
Gregory Goto: 76
Erick Kawakami: 32
Charly Kinoshita: 53
Anna Saito: 19

Ascending by value
========================
19: Anna Saito
32: Erick Kawakami
34: Steve Yamada
53: Charly Kinoshita
64: John Miyabe
76: Gregory Goto
87: Jeff Takeshita
97: Robert Suzuki
100: Mickey Yoshida

Descending by value
========================
100: Mickey Yoshida
97: Robert Suzuki
87: Jeff Takeshita
76: Gregory Goto
64: John Miyabe
53: Charly Kinoshita
34: Steve Yamada
32: Erick Kawakami
19: Anna Saito

まとめ

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

写経してみた(ARKit)

はじめに

前々から ARKit さわってみたいな〜と思いつつずっとさわってなかったんですが最近ずっと引きこもってて時間があるので ARKit をさわってみました。
新しいことを習得するには守破離の精神からいって「守」つまり真似することが大事かなと思います。プログラミングでいうと写経ですね。

ということで ARKit で写経してみました。

ar_sample

環境

  • Xcode 11.5
  • Deployment Target 13.0

とりあえずAR表示

今まで ARKit を全くさわってなかったのでほぼ何もわからない状態です。。。とりあえず ARKitのサンプルコード集「ARKit-Sampler」 を参考に 3D モデルを表示してみました。
手順は下記

  1. SceneKit Catalog を追加
    scenekit
  2. 3D モデルを追加(参考サイトのサンプルのship追加)
  3. Info.plist に Privacy - Camera Usage Description 追加
    info_plist
  4. IB上で ARSCNView 追加(ViewController に接続)
    ib
  5. ARKit.framework 追加(これがないとlink errorになった。。。)
    framework
  6. ViewController にコード記載
import UIKit
import ARKit

final class ViewController: UIViewController {

    @IBOutlet private weak var sceneView: ARSCNView!
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        sceneView.scene = SCNScene(named: "art.scnassets/ship/ship.scn")!
        let config = ARWorldTrackingConfiguration()
        sceneView.session.run(config)
    }
}

これだけで AR が実現できます:clap:(もっと AVCapture とかでゴリゴリしないといけないと思ってました。。。)

写経

とりあえず 3D モデルが簡単に表示できることはわかった。次に何やろうと考えたときに 3D 空間に般若心経を写経したい!と思い至りました!!
写経するのに必要なのは下記

  1. 文字を表示する
  2. 文字にフェードアニメーションを付ける

とりあえずこの2つができれば写経できるはず!

文字を表示する

こちら(ARKitのAR文字をキレイにした話)を参考に文字表示してみました。とりあえず文字表示は SCNText を使うみたい。
まるっとコピペですがこれで表示できるみたいです。

//カメラの現在位置を取得する
guard let camera = sceneView.pointOfView else { return }

let textGeometry = SCNText(string: message, extrusionDepth: 0.8)
textGeometry.firstMaterial?.diffuse.contents = UIColor(named: "ArizarARFontColor")
textGeometry.font = UIFont(name: "HiraginoSans-W6", size: 100)
let textNode = SCNNode(geometry: textGeometry)
let position = SCNVector3(0,0.1,-0.1)
textNode.position = camera.convertPosition(position, to: nil)
//カメラの向きに合わせる
textNode.eulerAngles = camera.eulerAngles
//大きさ設定
textNode.scale = SCNVector3(0.0001,0.0001,0.001)

sceneView.scene.rootNode.addChildNode(textNode)

文字にフェードアニメーションを付ける

こちら(SceneKitのアニメーションサンプル集)を参考にアニメーションを付けてみました。アニメーションには SCNAction を使うみたい。fadeIn っていうそれっぽいのがあったので使いました。

textNode.opacity = 0.0 // 0にしておく
let action = SCNAction.fadeIn(duration: 0.2)
textNode.runAction(action)

ちょっとひっかかったのが fadeInopacity を 1.0 に変更してくれるやつなのでもともとの opacity を下げとかないと何も起きません。

全体の実装

import UIKit
import ARKit
import SceneKit

final class ViewController: UIViewController {

    @IBOutlet private weak var sceneView: ARSCNView!
    private var texts = [
        "仏説摩訶般若波羅蜜多心経",
        "観自在菩薩", "行深般若波羅蜜多時", "照見五蘊皆空", "度一切苦厄",
        "舎利子", "色不異空", "空不異色", "色即是空", "空即是色",
        "受想行識亦復如是", "舎利子", "是諸法空相", "不生不滅", "不垢不浄", "不増不減",
        "是故空中", "無色", "無受想行識", "無眼耳鼻舌身意", "無色声香味触法", "無眼界", "乃至無意識界",
        "無無明", "亦無無明尽", "乃至無老死", "亦無老死尽",
        "無苦集滅道", "無智亦無得", "以無所得故", "菩提薩埵", "依般若波羅蜜多故", "心無罣礙", "無罣礙故", "無有恐怖", "遠離一切顛倒夢想",
        "究竟涅槃",
        "三世諸仏", "依般若波羅蜜多故", "得阿耨多羅三藐三菩提", "故知般若波羅蜜多",
        "是大神呪", "是大明呪", "是無上呪", "是無等等呪", "能除一切苦", "真実不虚", "故説般若波羅蜜多呪", "即説呪日",
        "羯諦", "羯諦", "波羅羯諦", "波羅僧羯諦", "菩提薩婆訶", "般若心経"
    ]

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        sceneView.scene = SCNScene()
        let config = ARWorldTrackingConfiguration()
        sceneView.session.run(config)
    }

    @IBAction private func start(_ sender: Any) {
        guard let camera = sceneView.pointOfView else { return }
        // カメラ中央手前に表示
        let startPosition = camera.convertPosition(SCNVector3(0, 0, -0.5), to: nil)
        // 文字サイズたぶん3cm
        let textSize: Float = 0.03
        var index = 0
        var x = startPosition.x
        for text in texts {
            var y = startPosition.y
            for t in text {
                let textGeometry = makeSCNText(String(t))
                let textNode = SCNNode(geometry: textGeometry)
                textNode.position = SCNVector3(x, y, startPosition.z)
                let scale = 1 / (textGeometry.boundingSphere.radius * 2) * textSize
                textNode.scale = SCNVector3(x:scale, y:scale, z:scale)
                textNode.opacity = 0.0
                y -= (textSize + textSize/3)
                let action = makeFadeAnimation(index: index)
                textNode.runAction(action)
                sceneView.scene.rootNode.addChildNode(textNode)
                index += 1
            }
            x -= (textSize + textSize/3)
        }
    }

    private func makeSCNText(_ text: String) -> SCNText {
        let textGeometry = SCNText(string: text, extrusionDepth: 0.2)
        textGeometry.firstMaterial?.diffuse.contents = UIColor.white
        textGeometry.font = .systemFont(ofSize: 1)
        return textGeometry
    }

    private func makeFadeAnimation(index: Int) -> SCNAction {
        let duration = 0.2
        let waitAction  = SCNAction.wait(duration: duration * Double(index))
        let fadeAction  = SCNAction.fadeIn(duration: duration)
        return SCNAction.sequence([waitAction, fadeAction])
    }
}

課題

とりあえず動くものはできましたがまだどの Node をどれの Child にすべきかとかはよくわかってないです。。。
文字サイズを決めてる let scale = 1 / (textGeometry.boundingSphere.radius * 2) * textSize もいまいちなんでこれで計算できるのかわかってません:weary:

「観」とか一部の文字がなぜか表示できませんでした。

おいおい勉強していこうと思います:muscle:

さいごに

これをやるために般若心経についてちょっと調べました(2冊本読んだ:sunglasses:)がすべてのものは存在するようで存在しないものなんだとか。
みなさんも開発で仕様がコロコロ変わるのを経験したことがあると思いますがそういうときにイライラしてはいけません。仕様もまた存在するようで存在しないものなのです。そう、仕様もまた「空」なのです:innocent:

これ:point_right:「写経」を自動化し、オートで功徳を積める仕組みを作ってみたのでございます。みたときからやりたかった:blush:

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む