投稿者: itkuma

  • CloudKit iCloudにサインインできない

    CloudKitを学習しようとサンプルプログラムをダウンロードしたり、参考になるサイトをまねてみたりして、実行させるとなぜか

    「iCloudにサインインしてからにして」

    みたいなメッセージが出てしまう。iPhoneでも、macでもiCloudにサインインして、driveを有効にしているのに、なぜなのか。途方に暮れてしまいました。こういう時はいつも、Apple Developer Ducumentationサイトを確認することにしています。CloudKitを一つ一つ見ていくと、Share Recordsにサンプルプログラムがありました。今まで見つけられなかったサンプルプログラムです。こういう時は、宝物でも見つけた気分になります。

    早速ダウンロードして、実行して見ます。

    「iCloudにサインインしてからにして」

    みたいなメッセージがまた出てしまう。

    今度は、ひとつひとつコードを見ていきます。

    「iCloudのcontainer identifierが”iCloud.<bundle identifier>”でなければcontainer作る時は

    CKContainer(identifier: <your container ID>)

    を使え!!」(もとは英語です。結構意訳してます。)

    いままで見なかったコメントでした。早速変更して・・・。

    今度はエラー

    「CloudKitShare.entitlementsがどうたらこうたら」

    ちょっとイラっときて、ファイルからCloudKitShare.entitlementsを消してあげました。再度Signing & CapabilitiesでiCloudのContainersを設定して・・・。CloudKitShare.entitlementsはできません。

    「エラーが消えてる。!」

    ダメもとで、早速実行。

    「うごいた。」

    結局、コメントをよく読むと、Bundle Identifierの頭に「iCloud.」をつけたContainerであれば、

    let container = CKContainer.defualt()

    Bundle Identifierの頭に「iCloud.」をつけたContainerでなければ、

    let container = CKContainer(identifier: <your container ID>)

    にする。ただし、<your container ID>の頭は iCloud. で始まらなければいけないということでした。

  • 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で作成するプロジェクトでは@mai 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()
    }

    こんな感じです。

  • Swift MapKit JSを触ってみました

    JavaScriptを使ってWebサイトに地図を埋め込めるフレームワークです。

    利用にはApple Developer Accountが必要です。取得するにはApple Developer Program(詳しくはこちら)に登録しなければなりません。年間登録料(99米ドル)が必要です。

    サポートしているブラウザは下記です。

    • Firefox 79 以降
    • Google Chrome 109 以降 (デスクトップモードのみ)
    • Microsoft Edge
    • Safari 13.1 以降

    下記のサイトを参考に触ってみました。

    参考サイト

    https://developer.apple.com/documentation/mapkitjs/creating_a_maps_token?changes=latest_minor(英語)はTokenの取得の仕方がわかります。

    https://developer.apple.com/jp/maps/sample-code/(日本語)はサイトへの載せ方がわかります。HTMLドキュメント(Java Script付きです)のサンプルがあります。

    地図の埋め込みのサンプルを使って、下記のコードを埋め込むと

    <style>
    #map-container {
        width: 100%;
        height: 600px;
    }
    </style>
    <script 
      src="https://cdn.apple-mapkit.com/mk/5.x.x/mapkit.core.js"
      crossorigin async
      data-callback="initMapKit"
      data-libraries="map"
      data-token="ここは取得したTokenです。"
    ></script> 
    <script type="module">
    // Wait for MapKit JS to be ready to use.
    const setupMapKitJs = async() => {
        // If MapKit JS is not yet loaded...
        if (!window.mapkit || window.mapkit.loadedLibraries.length === 0) {
            // ...await <script>'s data-callback (window.initMapKit).
            await new Promise(resolve => { window.initMapKit = resolve });
            // Clean up.
            delete window.initMapKit;
        }
    };
    
    /**
     * Script Entry Point
     */
    const main = async() => {
        await setupMapKitJs();
    
        const kobe = new mapkit.CoordinateRegion(
            new mapkit.Coordinate(34.69, 135.1955),
            new mapkit.CoordinateSpan(0.1, 0.1)
        );
    
        // Create a map in the element whose ID is "map-container".
        const map = new mapkit.Map("map-container");
        map.region = kobe;
    };
    
    main();
    
    </script>
    <body><div id="map-container"></div></body>

    こんな感じです。

  • PowerAutomate json関数を触ってみました

    配列型のJSONデータを配列変数に代入するには、JSON解析から配列変数に割り当てる方法と、json関数に代入して、配列変数に割り当てる方法があります。JSON解析は構造解析という手間がかかりますが、json関数は構造解析しなくても変換できます。

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

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

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

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

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