投稿者: itkuma

  • CloudKit Console レコードタイプが削除できない

    CloudKitを試そうと色々触っているうちにレコードタイプが消せなくなりました。出てくるダイアログを見ると、

    “invalid attempt to delete a record type which is active in a production”

    とメッセージが出て消せません。どうやら、

    「本番コンテナでアクティブなレコード タイプを削除しようとする試みは無効です。」

    といった意味なようです。本番コンテナー?いつした?どこでした?疑問の嵐が巻き起こりです。それから、https://developer.apple.com/documentation/cloudkitを調べてみました。次のようなことがわかりました。私の悪い癖で、説明書とかを読みながらさわればよさそうなものを、適当に触ってつまずいてから、なんでだろうと調べ出すのは悪い癖なんですが、治りません。でも、安心してください。壊れて困るようなものを触る時は必ず説明書等を読みます。

    さて、どうしたら本番環境になるのかですが、Apple Developer Programに登録されていることを前提にして進めます。

    まず、CloudKit DatabaseへはAccount – Apple Developerからも入れます。

    Xcodeからも入れますが、その説明は割愛します。

    Account – Apple Developerのサイトの下記

    赤四角マークのCloudKitをクリック

    赤四角マークのCloudKit Databaseをクリックして、データベースの管理画面に入れます。

    CloudKit Databaseを開くと、左下に下の表示があります。(赤四角や青四角はありません。)

    赤四角のDeploy Schema Changes を実行すると下のような表示が出ます。Schemaの変更をするとここに表示され、右下のDeployボタンをクリックすると、変更したSchemaがDevelopment(開発環境)からProduction(本番環境)へ保存されます。

    そして、

    ただし、レコードタイプは開発環境から本番環境に保存されますが、レコードは開発環境から本番環境に保存されません。

    また、青四角のReset Environmentを実行すると、すべての開発環境のレコードタイプおよびレコードは削除されます。本番環境のレコードタイプおよびレコードは削除されません。本番環境で編集する必要があるようです。本番環境にアプリを移行していなければ、この操作は必要なさそうです。

    開発環境と本番環境の切り替えですが、コンテナ名の右に下の表示があります。そこで開発環境と本番環境を替えらえます。

    上の表示をクリックすると、下の表示が出ますので、そこで環境を選べます。

  • Swiftのasyncとawaitについて調べてみました

    asyncはasynchronousの略のようです。訳は、非同期の、同じ速度で進まない、同時に起こらないといったようなことです。asyncは実行の途中で一時停止できる特別な種類の関数またはメソッドを示します。また、async letのように組み合わせて使うと、他の処理を先行させることもできます。awaitは途中で一時停止の可能性があるポイントを明示するためのマークのようです。例えば、

    async let 非同期1 = await 遅延関数1(1)
    
    //順番に実行されます
    print("after1")
    
    //順番に実行されます
    let 普通2 = 関数1(2)
    
    //順番に実行されます
    print("after2")
    
    //同一関数は一度に一つしか実行されません
    async let 非同期3 = await 遅延関数1(3)
    
    //順番に実行されます
    print("after3")
    
    //遅延関数1とは異なる関数なので遅延関数1が終わるより先に実行されます
    async let 非同期4 = await 遅延関数2(4)
    
    //順番に実行されます
    print("after4")
    
    //順番に実行されます
    let 普通4 = 関数1(5)
    
    //順番に実行されます
    print("after5")
    
    /*
    after1
    Check Number: 2
    after2
    after3
    after4
    Check Number: 5
    Check Number: 4
    after5
    Check Number: 1
    Check Number: 3
    */
    
    
    func 遅延関数1(_ check: Int) async -> String {
        for _ in 1...1000000 {
        }
        print("Check Number: \(check)")
        return ("遅延1-\(check)")
    }
    func 遅延関数2(_ check: Int) async -> String {
        for _ in 1...100000 {
        }
        print("Check Number: \(check)")
        return ("遅延2-\(check)")
    }
    
    
    func 関数1(_ check: Int) -> String {
        print("Check Number: \(check)")
        return ("普通\(check)")
    }

    こんな感じです。asyncと明示した関数、メソッド、変数を参照するときはawaitをつけないとコンパイラーエラーになります。async letを使いawaitをつけいなとコンパイラーに警告されますが、実行されます。しかし、awaitをつけておけば、どこでasyncの関数やメソッドを参照しているかが、後でみてわかりやすくなるので、asyncとawaitはセットで使うことにしておいた方がよさそうです。

  • Swiftのenumについて調べてみました

    enumは列挙型と呼ばれます。

    enum Seasons {
        case Spring
        case Summer
        case Autumn
        case Winter
    }

    のように主にcaseを用いて定義されます。それから、switch式とよく組み合わせて使います。

    var myFavorite = Seasons.Spring
    
    switch myFavorite {
        case .Spring:
            print("どことなく気持ちが浮かれますよね")
        case .Summer:
            print("何かしなくちゃって気がせきますね")
        case .Autumn:
            print("旅に出たくなりますよね")
        case .Winter:
            print("一人が落ち着きますよね")
    }
    
    //どことなく気持ちが浮かれますよね

    CaseIterableプロトコルに準拠させるとcaseを配列のように扱えます。但しcaseをassociated Valueとするとエラーになります。

    enum Seasons: CaseIterable {
        case Spring
        case Summer
        case Autumn
        case Winter
    }

    これはOKですが、caseをassociated Valueにして見ると

    enum Seasons: CaseIterable {
        case Spring(month: String)
        case Summer(month: String)
        case Autumn(month: String)
        case Winter(month: String)
    }

    これはエラーになります。しかし、associated ValueでもallCaseを使いたいケースもあります。そんな時はallCaseを具体的な値の配列で定義してあげれば使えます。例えば

    enum E干支時刻: CaseIterable {
    	//associated Value
    	case eto(kanji: String, yomi: String, startJi: Int, shouJi: Int, endJi: Int)
    
    	//CaseIterableプロトコルに準拠させる為
    	//allCasesをassociated Valueを具体化して定義します。
    	static var allCases: [E干支時刻] {
    		return [.eto(kanji: "子", yomi: "ね", startJi: 23, shouJi: 0, endJi: 1),
    			.eto(kanji: "丑", yomi: "うし", startJi: 1, shouJi: 2, endJi: 3),
    			.eto(kanji: "寅", yomi: "とら", startJi: 3, shouJi: 4, endJi: 5),
    			.eto(kanji: "卯", yomi: "う", startJi: 5, shouJi: 6, endJi: 7),
    			.eto(kanji: "辰", yomi: "たつ", startJi: 7, shouJi: 8, endJi: 9),
    			.eto(kanji: "巳", yomi: "み", startJi: 9, shouJi: 10, endJi: 11),
    			.eto(kanji: "午", yomi: "うま", startJi: 11, shouJi: 12, endJi: 13),
    			.eto(kanji: "未", yomi: "ひつじ", startJi: 13, shouJi: 14, endJi: 15),
    			.eto(kanji: "申", yomi: "さる", startJi: 15, shouJi: 16, endJi: 17),
    			.eto(kanji: "酉", yomi: "とり", startJi: 17, shouJi: 18, endJi: 19),
    			.eto(kanji: "戌", yomi: "いぬ", startJi: 19, shouJi: 20, endJi: 21),
    			.eto(kanji: "亥", yomi: "い", startJi: 21, shouJi: 22, endJi: 23)]
    	}
    }

    こんな感じです。これをforEachで回してみます。

    E干支時刻.allCases.forEach { e干支時刻 in
    	switch e干支時刻 {
    	case .eto(let kanji, let yomi, let startJi, let shouJi, let endJi):
    			print("\(kanji)(\(yomi))の刻は \(startJi)時から\(endJi)時です。正\(kanji)は\(shouJi)時です。")
    	}
    }
    /*
    子(ね)の刻は 23時から1時です。正子は0時です。
    丑(うし)の刻は 1時から3時です。正丑は2時です。
    寅(とら)の刻は 3時から5時です。正寅は4時です。
    卯(う)の刻は 5時から7時です。正卯は6時です。
    辰(たつ)の刻は 7時から9時です。正辰は8時です。
    巳(み)の刻は 9時から11時です。正巳は10時です。
    午(うま)の刻は 11時から13時です。正午は12時です。
    未(ひつじ)の刻は 13時から15時です。正未は14時です。
    申(さる)の刻は 15時から17時です。正申は16時です。
    酉(とり)の刻は 17時から19時です。正酉は18時です。
    戌(いぬ)の刻は 19時から21時です。正戌は20時です。
    亥(い)の刻は 21時から23時です。正亥は22時です。
    */

    こんな感じになります。

  • Swiftのprotocolについて調べてみました

    protocolは、特定のタスクや機能に適したメソッド、プロパティ、その他の要件の設計図を定義します。とのことです。

    設計図の定義ということですが、プロパティ名は作れても、値は設定できません。メソッド名は作れても処理を書くことはできません。値の設定や処理を書くことは、protocolに準拠したclass、struct、enumでしかできません。

    また、継承はclassしかできません。protocolの場合は準拠というようです。

    共通の要件を設定しようとしたとき、struct、enumではprotocolを使うしかありません。

    ところで、classでは値の設定や、処理を書くことができるので、どの継承部分の設定や、処理を引き継いでいるか管理するのに大変そうです。

    「何代前のご先祖様はこんなことがこんだけできたけど、お前はできないんだったら、変更しておけよ!」

    って叱られそうです。

    その点、protocolは準拠させるときに具体的に要件を設定すればいいので、

    「出来そうなことを書いとくから、後はどんなふうにどれだけできるかはその都度設定してね!」

    みたいな軽い感じがします。

    さらに、protocolは型として認識されるので、funcの引数に設定できます。例えば、

    protocol PersonProtocol {
    	var name: String {get set}
    }
    
    //protocol PersonProtocol に準拠したprotocol AdultPersonProtocolを定義します
    protocol AdultPersonProtocol: PersonProtocol {
    	var job: String {get set}
    }
    
    //protocol PersonProtocol に準拠したstruct PersonAを定義します
    struct PersonA: PersonProtocol {
    	var name: String
    	init(){
    		name = ""
    	}
    }
    
    //protocol AdultPersonProtocolに準拠したstruct PersonBを定義します
    struct PersonB: AdultPersonProtocol {
    	var name: String
    	var job: String
    	init(){
    		name = ""
    		job = ""
    	}
    }
    
    //struct PersonAを実装したpersonAを定義します
    var personA = PersonA()
    personA.name = "子供店長"
    
    //struct PersonBを実装したpersonBを定義します
    var personB = PersonB()
    personB.name = "大人店長"
    personB.job = "サラリーマン"
    
    //ここでprotocol PersonProtocolをfuncの引数personの型に設定します
    func printName(_ person: PersonProtocol) {
    	//protocol PersonProtocolのプロパティnameに設定された値を表示します
    	print(person.name)
    }
    
    printName(personA)
    //子供店長
    printName(personB)
    //大人店長  

    こんな感じです。protocolのAdultPersonProtocolはPersonProtocolに準拠しているので、PersonProtocol型でもあります。ですから、この場合の引数として有効です。

  • Swiftのclassとstructについて調べてみました

    結論としては、特にこだわりが無ければ、structを使う方がよいようです。

    classの継承を使いたいときや、Object-Cと連携させたいときはclassを使わないといけないようです。

    参照渡しを利用したいとき。つまり、

    struct TestStruct {
    	var sampleStruct: String 
    	init(){
    		sampleStruct = ""
    	}
    }
    
    class TestClass {
    	var sampleClass: String 
    	init(){
    		sampleClass = ""
    	}
    }
    
    var testStruct = TestStruct()
    var testClass = TestClass()
    
    testStruct.sampleStruct = "Hello"
    testClass.sampleClass = "Hello"
    
    var ts1 = testStruct
    var ts2 = testStruct
    var tc1 = testClass
    var tc2 = testClass
    
    ts1.sampleStruct = "なんでやねん"
    tc1.sampleClass = "なんでやねん"
    
    print("structは値渡しなのでts2.sampleStructは\(ts2.sampleStruct)のままです。")
    //structは値渡しなのでts2.sampleStructはHelloのままです。
    print("classは参照渡しなのでtc2.sampleClassは\(tc2.sampleClass)に変わります。")
    //classは参照渡しなのでtc2.sampleClassはなんでやねんに変わります。
    

    上記のように、変数testStruct、testClassに実装し、プロパティtestStruct.sampleStruct、testClass.sampleClassに”Hello”を代入後、変数ts1、ts2に変数testStruct、tc1、tc2にtestClassを代入し、プロパティts1.sampleStruct、tc1.sampleClassを”なんでやねん”に変更した時、

    structの場合、ts2.sampleStructは”Hello”のままですが、

    classの場合、tc2.sampleClassは”なんでやねん”に変わります。

    ということで、プロパティの値を変更したら、他のも変更させたいときはclassを使うようです。

  • SwiftUIのアプリはどこから始まるのか調べてみました

    XCodeで作成するプロジェクトでは@main attributeがあるstructから始まります。

    import SwiftUI
    
    @main
    struct MyApp: App {
        var body: some Scene {
            WindowGroup {
                ContentView()
            }
        }
    }
    

    iOSを対象にしたSwiftUI Interfaceではこんな感じです。下記のファイルと合わせると、地球マークの下に「こんにちは!」と表示されたアプリが出来上がりです。

    import SwiftUI
    
    
    struct ContentView: View {
        var body: some View {
            VStack {
                Image(systemName: "globe")
                    .imageScale(.large)
                    .foregroundStyle(.tint)
                Text("こんにちは!")
            }
            .padding()
        }
    }
    
    
    #Preview {
        ContentView()
    }

    こんな感じです。

  • PowerApps PDFビューアーを触ってみました

    PowerAppsには、PDFを表示する機能があります。

    はじめはPowerAutomateで下記の関数を使い、帰ってきた、バイナリデータをSet関数で変数に代入し、その変数をPDFViewerのDocumentプロパティにセットし、PDFを表示させていたのですが。

    dataUri(base64ToBinary(body('ステップ名')?['$Content']))

    PowerAppsだけでも、データでデータの追加 コネクタでBoxを追加すると、Box.GetFileContent(“Box.File.Id“)が使えるようになり、Set関数で変数に代入し、その変数をPDFViewerのDocumentプロパティにセットすれば表示できますした。こちらの方が簡単なので、今はこの方法を使っています。

  • PowerApps Launchを触ってみました

    自作アプリから別の自作アプリへ移動する時Launch関数を使います。

    Launch("url")

    urlにparameter &web=1をつけるとブラウザーで開くことができます。

    Launch("url&web=1")

    Teams内のPowerAppsで作成されたアプリを参照する場合、一度チャネルのタグに登録し、チャネルに認識させないと、アプリオーナー以外のチームメンバーが参照できません。タグ登録した後、タグを削除し、Teams上にアプリ登録し、そのurlを取得し、Launchのparameterとして設定すればアプリオーナー以外のチームメンバーも参照できます。

  • PowerApps Patchを触ってみました

    PowerAppsでJSONデータをテーブルにして、レコードの内容を変更して、テーブルに反映させる。

    まずはJSONの簡単なサンプルを変数_JSONtextにセットします。

    Set(_JSONtext,"[{""A"": ""A1""},{""A"": ""A2""}]")

    ParseJSON関数を使いコレクション_tableにセットします。この時ClearCollectionを使うのが味噌です。Patch関数の第一引数はコレクションなので、単純にSet関数を使ってしまうと、_tableを参照できませんでした。

    ClearCollect(_table,ForAll(ParseJSON(TextBoxJSONSample.Value),{A:Text(ThisRecord.A)}))

    _tableをGallary1のItemsにセットします。

    Gallary1でレコードをSelectされたらレコードの内容を反映させるFormを作成します。FormのDataSourceに_tableをセット、ItemにGallary1.Selectedをセット、DataCardを追加し、その中にTextBox2をセットし、ValueにThisItem.Aをセットします。これでGallary1で選択したレコードのAがTextBox2に表示されます。

    TextBos2の内容を変更し、その変更を_tableに反映させるのにPatch関数を使います。

    Patch(_table,First(Filter(_table,A = Gallery1.Selected.A)),{A: TextBox2.Value})

    この第二引数First(Filter(_table,A = Gallery1.Selected.A))でわかるように、レコードを特定する必要があります。JSONデータを作成するときには重複しないデータをもつプロパティを設定する必要があります。

    コレクションをJSONデータにします。

    Set(_JSONtext,JSON(_table))
  • 初めての金継ぎ

       初めての金継ぎ

     パートナーのお気に入りの箸置きが割れま

    した。しばらく放置されていたのですが、ど

    うやら金継ぎをして欲しそうなそぶりです。

    金継ぎはやったことがないし、そもそも漆を

    どこで手に入れたらいいのかわかりませんで

    した。とりあえず東急ハンズへ行ってみると、

    売ってました。漆はそんなに高くはなかった

    のですが、金継ぎする金泥と言われるものが

    結構値が張るものでした。代替品として、真

    鍮泥があるそうですが、東急ハンズにはあり

    ませんでした。ネットを調べると売っていた

    ので買い入れました。

     まずは接着するための麦漆作りです。薄力

    粉、水、生漆で作ります。薄力粉を練って耳

    たぶぐらいの硬さになったら、水に入れて揉

    み澱粉を抜きます。はじめは溶けてしまうん

    じゃないかと心配でしたが、逆に固くなりま

    した。それに生漆を混ぜていきます。麦漆が

    糸を引く位が良いそうですが、なぜか焦って

    しまい、糸を引く前に接着に使ってしまいま

    した。筆で塗るようなことを書いてあったん

    ですが、固くて(当然です。気が早すぎるの

    です。)爪楊枝で接着面になすりつけて、ぐ

    いと接着させてみたら、なんとなくひっつき

    ました。そして二週間放置しました。結構し

    っかりと接着できたように思います。次に砥

    の粉、水、生漆で錆と言われるもので、小さ

    な欠けを埋めました。そしてまた二週間放置

    します。そして下地に生漆を塗って二週間放

    置します。そして黒漆を塗って真鍮泥を蒔く

    作業の時、3時間置いたら乾きすぎました。

    真鍮泥がうまくつきませんでした。紙やすり

    で削って(これができるから失敗しても安心)

    もう一度。今度は黒漆を塗って30分ほどで

    真鍮泥を蒔き、3時間(半日以上おいたほう

    が良かったかもしれません。)ほど放置しま

    した。はみ出た部分は水洗いで取れました。

    いよいよ最後の透漆で固める作業です。生漆

    を練って練って、白濁が消えるくらいになっ

    たところで、真鍮泥を蒔いた部分に塗りティ

    ッシュですぐに押さえるようにして余分な漆

    を取ります。なんとなく金継ぎらしいものが

    出来上がりました。パートナーも初めてにし

    ては上出来きと褒めてくれました。

     ちなみに漆を塗る時の筆ですが、使い終わ

    った後は油で洗って、さらにテレピンで油を

    洗いとり、乾かすとありましたが、テレピン

    の購入をパートナーに断固拒否され、代わり

    に、食器洗い洗剤を使いました。最後に水洗

    いをして乾かして何度も使いました。また、

    真鍮泥を蒔く時真綿ではなく、化粧用の筆を

    使いました。