簡単なアプリができたので、試しにTestFlightに登録してみようと、XCodeでarchiveをかけて登録しようとしたら、iconの透過ができないかアルファを含んでるとかなんとかで登録できませんでした。結局ファイル書き出し時にPNG形式にして、アルファのチェックを外した物をアイコンにしたらすんなり通りました。assetsに登録時に教えてほしいけど、Apple Developer Programに登録してなくてもアプリを作れるから、その辺はルーズにしてあるのかも・・・。以後気を付けます。
投稿者: itkuma
-
逃げる
逃げる
逃げるということになぜか、恥ずかしいと
か、卑怯というような、イメージを植え付け
られている気がします。
逃げるという言葉の意味を調べてみると、
危険や煩わしいことから積極的に遠ざかると
か、追手の力の及ばないところに身を置くと
か、競技においては首位を行くものが後続す
るものに追いつかれないで勝つといった意味
でした。恥ずかしさを感じたり、卑怯なこと
をしているイメージはなさそうです。どこで
そんなイメージを植え付けられたんでしょう。
私が小さい頃のテレビの中の人が時々
「卑怯者、逃げるな!」
みたいなことを言っていたのを思い出します。
どうやら、逃がした側の感情のようです。そ
こから恥ずかしいという感情も派生したので
しょうか。どちらにしても逃げる側がその行
為に負の感情を抱く必要はみじんもなさそう
です。逃げた先で安心な暮らしができれば、
逃げきっての勝ちといったところでしょうか。
-
SwiftUIの@Observableと@Environmentについて調べてみました
SwiftUIの@Observableをクラスに適用すると、そのクラスを@EnvironmentでViewに導入すると、そのクラスのプロパティに変更を加えた時その変更を随時Viewに適用してくれます。
下記コードはTestObservableクラスに@Observableを適用し、ContentViewに@Environmentでそのクラスを導入したものです。
旧姓、新姓のボタンをクリックすると、クラスのnameプロパティを変化させます。その変化に対応しクラスのnameプロパティをセットしたTextの表示が変化します。
PreviewもViewにenvironmentでクラスを導入することで、Previewも変化します。
import SwiftUI struct ContentView: View { @Environment(TestObservable.self) var testObservable var body: some View { Text(testObservable.name) Button { testObservable.changeName(name: "旧姓") } label: { Text("旧姓") } Button { testObservable.refreshName() } label: { Text("新姓") } } } @Observable class TestObservable { var name: String init() { self.name = "新姓" } func refreshName() { self.name = "新姓" } func changeName(name: String) { self.name = name } } #Preview { ContentView() .environment(TestObservable()) }
@mainからの呼び出しは下記の感じです。
import SwiftUI @main struct SwiftUILearnApp: App { var body: some Scene { WindowGroup { ContentView() .environment(TestObservable()) } } }
-
暑さ寒さも彼岸まで
暑さ寒さも彼岸まで
2024年の夏は暑かった。今までにない
というか、年齢のせいかもしれませんが、暑
くて、陽の出ている時間にサックスを吹きに
行く気がしませんでした。
9月になっても暑い日が続き、彼岸過ぎて
も暑いのではと思っていると、彼岸前の雨で
急に気温が下がり、お彼岸には日陰で風にあ
たると心地よく感じられるようになりました。
「暑さ寒さも彼岸まで。」
よく使われる言葉ですが、この時はほんとに
実感しました。というよりなんだかありがた
みさえ感じました。涼しくなったのは、言葉
のおかげではないのですが、昔からある言葉
の情景が今もまだあることへの感謝なのかも
しれません。
-
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を使うようです。