LaunchDaemonsのplistファイルはroot権限でないと動作しない
- ログイン時にアプリに起動させるために
/Library/LaunchDaemons以下に.plistを配置することがある - このplist内のパラメータを変更しようとした際に、書き込み権限の都合上、別の場所に移して編集してそれを戻すことをした際に、plistが機能しなくなってしまった。
- これはplistのOwnerが変わってしまったためで、root権限である必要があるとのこと
# 編集前 LaunchDaemons % ls -l@ -rw-r--r-- 1 root wheel 985 12月 24 17:35 xxx.Service.plist # 編集後 LaunchDaemons % ls -l@ -rw-r--r--@ 1 <user> wheel 1032 1月 23 09:31 xxx.Service.plist com.apple.lastuseddate#PS 16 com.apple.metadata:kMDLabel_mymlunohiynfcncabiqhirhatm 121 com.apple.xcode.PlistType 0
macos - Why am I getting a "dubious ownership of file" error when Launch Agent runs my .plist file? - Ask Different ユーザーごとの設定ファイル(LaunchAgents)は、それをロードするユーザーの所有者である必要があります。システム全体のデーモン(LaunchDaemons)はすべて、rootの所有者である必要があります。設定ファイルは、グループまたはワールドレベルの書き込み権限を持つべきではありません。これらの制限はセキュリティ上の理由から設けられています。launchd設定ファイルへの書き込み権限を与えると、どの実行ファイルが起動されるかを指定できるようになるためです。
- 対応策としては最初からviで直接編集するか、ファイルの権限をchmodで戻すといいと思う
# viで編集する sudo vi xxx.plist # コマンドで権限をrootに戻す sudo chown root:wheel /Library/LaunchDaemons/myfile.plist
macOSの設定画面のレイアウト
概要
- macOSの設定画面のレイアウトのTipsが詳しく紹介されている
- 実際のAutoLayoutの方法はCotEditorの過去バージョンを参照すると非常に参考になった記憶 (現行はSwiftUIのため)
macOS15/UTMにおいてUS配列からJIS配列にキーボードの認識を変更する
- UTM/macOS15の仮装環境で、元のMacがJIS配列のキーボードだが仮想環境内でUS配列として認識されてしまう問題
- 検索すると
karabiner-elementsがいいらしい
- アプリをインストールし指示通り各種権限を許可した後、下記でJISを選択

- ただKarebiner-elementsのログで下記エラーがでる
[2025-06-02 15:15:51.629] [error] [console_user_server] grabber_client connect_failed: Connection refused
- そこでUTM側でキーボードを下記の通り変更することで、エラーがなくなり動作するようになった
- ただし英数/かなのキーだけがどうにも認識されず、今回は諦めた


- 仮想環境の今のキーボードの状態は下記から確認できる

- 尚エラーを解消する中でbrew経由で再インストールしている。これによって改善したわけではないと思うが念のための記録として。
Xcodeでマルチモジュール構成を試す
参考
- 【Swift】マルチモジュール構成を試してみた #iOS - Qiita
- 主に参考にさせてもらいました
- iOSアプリでSPMを用いたマルチモジュール構成を試してみた #Swift - Qiita
- プロジェクト構成が参考になりました
- 既存の Xcode プロジェクトを SwiftPM でマルチモジュール化する最初のステップ
- 【iOS】新規プロジェクトにSPMマルチモジュールを採用する際の手順書 #Swift - Qiita
手順
- 新規プロジェクトの作成

- File > New > Package...からパッケージ(各モジュール)を作成


- 今回
Coreというパッケージを作成 Add to:の設定を行い、プロジェクトにパッケージを追加させる

- Coreパッケージ内にソースコードを追加

- プロジェクト設定から先程作成したCoreのライブラリを追加

- 以上でアプリ本体からCoreライブラリを呼べることが確認できる

- (参考) モジュールのPackage.swift
// swift-tools-version: 6.1 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "GitHubAPIClient", platforms: [ .iOS(.v16), .macOS(.v10_15), ], products: [ .library( name: "GitHubAPIClient", targets: ["GitHubAPIClient"]), ], dependencies: [ // インポートするライブラリの指定 .package(path: "../GitHubRESTAPI"), .package(path: "../GitHubAPIQraphQL"), .package(url: "https://github.com/pointfreeco/swift-dependencies", from: "1.0.0"), .package(url: "https://github.com/kishikawakatsumi/KeychainAccess", from: "4.0.0"), ], targets: [ // ターゲットごとに利用するライブラリの指定 .target( name: "GitHubAPIClient", dependencies: [ "GitHubRESTAPI", "GitHubAPIQraphQL", .product(name: "Dependencies", package: "swift-dependencies"), .product(name: "DependenciesMacros", package: "swift-dependencies"), .product(name: "KeychainAccess", package: "KeychainAccess"), ], swiftSettings: [ // マクロを使うなら `macros` セクションを追加する必要がある .enableUpcomingFeature("Macros"), .enableExperimentalFeature("StrictConcurrency") ], ), .testTarget( name: "GitHubAPIClientTests", dependencies: ["GitHubAPIClient"] ), ] )
macOSでSentryのバイナリがx86_64となりユニバーサルバイナリにならない問題
- macOSアプリでSentryを利用しているが、アプリに含まれるSentryのバイナリがx86_64だけでユニバーサルバイナリとならない問題がでた
- 解決方法としては、静的ライブラリではなく、動的ライブラリの方を選択するといいとのこと
SentryではなくSentry-Dynamicのほうを選択

- (ドキュメントには軽くしか書かれていない)
https://docs.sentry.io/platforms/apple/install/swift-package-manager/
Sentry is the static framework, which is the recommended option if you prefer a fast app start time.
Sentry-Dynamic is the dynamic framework.
SentrySwiftUI is used to track performance of SwiftUI views, see more information in the docs.
- アプリ内の下記ファイルに対して
lipoをすることでアーキテクチャを確認できる

lipo -info Sentry.framework/Sentry Architectures in the fat file: Sentry.framework/Sentry are: x86_64 arm64 arm64e
SiriやWi-Fiのメニューバーアイコンファイルを参照する方法
- メニューバーアイコンのデザインについて考えている。ベースは以下。
- そこで参考としてSiriのメニューバーに表示されているアイコンのファイルを見てみたいと思ったので検索
- 下記にあるらしい
Where are Siri menu bar icon files located? /System/Library/CoreServices/Siri.bundle/Contents/Resources/Assets.car

Assets.carを開くには下記アプリがある- 下記の通り詳細が確認できる
- 2xのアイコンの大きさが知りたかったが28ptとわかった

- 同じ要領でWi-Fiのメニューバーのアイコンもみてみる
macOS Big Sur Wi-Fi icons location /System/Library/PrivateFrameworks/CoreWLANKit.framework/Versions/A/Resources/Assets.car
- サイズが20/40ptで違うかも…?名称も拡張子が.pdfだし…

- と思ったらPDFファイルはアイコンとして使えるらしい
Designing macOS menu bar extras Menu bar extra image assets can be a single SVG, a single PDF, or a pair of PNGs (1× and 2× scales for non-Retina and Retina displays). They can also be drawn with code, if you require something dynamic, like an analogue clock or a calendar icon that shows the day of the month.
- アイコンのサイズって自動的にいい感じにリサイズするんだったっけ…多分そのままだったような記憶だけど曖昧なのでまた時間があるときに試す
redefinition of module 'XXX'のエラー解消
- SwiftPMで
redefinition of module 'XXX'とエラーが出た - Xcodeの
Clean Build Folder、Reset Package Cachesでも改善せず
Go to Project root > BuildTools > .build > arm64-apple-macosx > release Delete ArgumentParser-tool.build and ArgumentParserToolInfo-tool.build Re-build the project
- 上記を参考に、私の場合は上記だけだと依然としてエラーだったので、
.buildのディレクトリを丸々削除することで解決した。
R.swiftの導入メモ
概要
- R.Swiftのプラグインの導入方法(Xcode project編)
- 基本この通り進める
- 利用例
- またR.swiftで文字列を置換する際、
Insert Patternを使うと対象を検索しやすい。(正規表現よりずっと簡単!)
検索バーの左にある虫眼鏡のアイコン> Insert Patternで
— kntk (@kntkymt) 2024年9月19日
文字/記号/改行/Any等のパターン指定の検索ができます。意外と便利なんですよこれ


エラーハンドリング
- またUIテスト側でR.swiftを利用しようとするとエラーが出た。stringシンボルが見つからないということで、
Localizable.stringsのTargetにをテスト側を追加すると解消した。
Value of type '_R' has no member 'string'

XcodeでInfo.plistの場所を変更する
Info.plistを下記のように別フォルダに移したい

- 単に移してビルドするとplistが見つからないというエラーがでるので、下記の
Info.plist Fileのパスを更新すればOK

- また下記の重複しているとのエラーが出たので
Copy Bundle ResourcesにInfo.plistがある場合はそれを消すと良い
Prepare build error: Multiple commands produce '/Users/ikeh/Library/Developer/Xcode/DerivedData/iOSEngineerCodeCheck-baojqjmcmqcbrrghemetsfapulot/Build/Products/Debug-iphonesimulator/iOSEngineerCodeCheck.app/Info.plist' note: Target 'iOSEngineerCodeCheck' (project 'iOSEngineerCodeCheck') has copy command from '/Users/ikeh/github-repository-search/iOSEngineerCodeCheck/Resources/Info.plist' to '/Users/ikeh/Library/Developer/Xcode/DerivedData/iOSEngineerCodeCheck-baojqjmcmqcbrrghemetsfapulot/Build/Products/Debug-iphonesimulator/iOSEngineerCodeCheck.app/Info.plist' note: Target 'iOSEngineerCodeCheck' (project 'iOSEngineerCodeCheck') has process command with output '/Users/ikeh/Library/Developer/Xcode/DerivedData/iOSEngineerCodeCheck-baojqjmcmqcbrrghemetsfapulot/Build/Products/Debug-iphonesimulator/iOSEngineerCodeCheck.app/Info.plist' Multiple commands produce '/Users/ikeh/Library/Developer/Xcode/DerivedData/iOSEngineerCodeCheck-baojqjmcmqcbrrghemetsfapulot/Build/Products/Debug-iphonesimulator/iOSEngineerCodeCheck.app/Info.plist'

古いnibファイルをXcodeで読み込む際にエラーになった際の対処方法
- かなり古いnibをXcodeで読み込もうとすると、下記のエラーが出て表示することすらできない問題にあたった。
Tried to create a document (class: IBXIBDocument) and got a document with a different, non-conforming fileType back instead.
- 一旦プロジェクトを閉じて、下記コマンドからxibへ変換を行ったファイルで置換することで解決した
ibtool LicenseInfo.nib --upgrade --write new/LicenseInfo.xib
SwiftPMの管理方法に、XcodeかPackage.swiftのどちらを採用するか
前提
- SwiftPMの管理方法には2種類ある
- Xcode上で管理する方法
- Package.swiftで管理する方法
- 特に理由がなければ基本的に
Xcode上で管理する方法を推奨
Package.swiftのユースケースと考慮する点
ユースケース
- 基本的に外部公開用パッケージ・マルチモジュール構成のときに利用される
- またDependabotやRenovateなどのライブラリのアップデートがあった際に、自動でPRをつくってくれるツールがあるが、この際に
Package.swiftを利用している必要がある - Xcodeの対応はIssuesにもあがっているが難しいみたい
https://team-blog.mitene.us/upgrade-swiftpm-library-renovate-71f7e8489775 Renovateのドキュメントに記載がある通り、 Package.swift 内のライブラリには対応していますが、Xcodeプロジェクトから入れたライブラリには対応していません。
考慮する点
- Package.swiftはXcodeに付随している依存関係解決ツールのバージョンまで指定しているので、Xcodeのバージョンアップをしたりすると動かなくなることがある
- 外部ライブラリにリソースを割くのが勿体ない
「Xcode上で管理する方法」の場合のライブラリのアップデート方針
- Renovateなどが利用できないので、ライブラリをアップデートするための方針を考える
- 例えば以下の例がある
DjangoやCeleryといった機能や影響が大きいフレームワークの場合、パッチバージョン(2.2.8→2.2.9) [1] の適用はこまめに行いましょう。
フレームワーク以外のライブラリ 1年に1回など、定期的にバージョンを更新していくのが良いでしょう。
開発用のツール flake8、mypy、pytest、toxといった開発中だけ使用するライブラリは、極端なことを言えばバージョンを上げる必要はありません。 半年以上継続する開発プロジェクトであれば、他のライブラリの更新時に合わせてバージョンアップする戦略が良いでしょう。
- またはあるiOSエンジニアの方に聞いた方針は以下の通り
- まずはライブラリのバージョンのルールを指定する
- 破壊的な変更があり得るかどうかで分けるといい
- Realmやアーキテクチャ系のライブラリなどの主要なライブラリは固定バージョン
- その他のライブラリは常に最新のMajorバージョンになるように指定
- 前者に関してライブラリの更新情報は随時キャッチアップしておき、影響がないかをチェックしたり、アップデートを検討する
- キャッチアップする工夫として、GASで検知してSlackのチャンネルに投稿したり、iOS Osushiを利用すると良い

@AppStorage用のキーとreset関数を提供するSwift Macrosの作成
概要
- Swift Macrosの習作として下記を作成するMacroを作成してみました。
- @AppStorageに渡すKey
- デフォルト値に戻すためのreset関数
- https://github.com/pommdau/userdefaults-key-macro
- (まだまだ理解が浅いので型推論の場合に未対応などいくつか問題は残っている)
モチベーション
- 開発しているアプリで下記のようなコードがあって、泥臭い実装でなんだかなーと思って棚上げしていた箇所を、Swift Macrosで解決できるのではと考えた
- 問題としては…
- 文字列指定をさけるための
enum Propertyの宣言が面倒 - 初期値を定義するための
defaultParameterとかもあまり良くない書き方そう
extension RopeSettings { enum Property: String, CaseIterable { case needsShadow case ropeWidth case ropeOpacity case elasticity // e.g. "GeneralSettings-shapeSize" var key: String { "\(className)-\(rawValue)" } func defaultParameter<T>() -> T { switch self { case .needsShadow: return true as! T case .ropeWidth: return 6.0 as! T case .ropeOpacity: return 1.0 as! T case .elasticity: return Elasticity.elastic as! T } } } private static var className: String { String(describing: self) } } extension RopeSettings { static func resetUserDefaults() { Property.allCases.forEach { userDefaultsKey in UserDefaults.standard.removeObject(forKey: userDefaultsKey.key) } } }
import SwiftUI class RopeSettings: ObservableObject { static let shared = RopeSettings() let settingsPaneType: SettingsPaneType = .rope // MARK: - User Settings @AppStorage(Property.needsShadow.key) var needsShadow: Bool = Property.needsShadow.defaultParameter() @AppStorage(Property.ropeWidth.key) var ropeWidth: Double = Property.ropeWidth.defaultParameter() @AppStorage(Property.ropeOpacity.key) var ropeOpacity: Double = Property.ropeOpacity.defaultParameter() @AppStorage(Property.elasticity.key) var elasticity: Elasticity = Property.elasticity.defaultParameter() init() { // Self.resetUserDefaults() } }
PyAutoGUIのlocateCenterOnScreenは例外を投げるという話
概要
サンプルコードで
locateCenterOnScreenの返り値がNoneかどうかを判断するものがあるが、現状は例外エラーが投げられる。- このようにエラーハンドリングをする
import pyautogui # force use of ImageNotFoundException pyautogui.useImageNotFoundException() try: location= pyautogui.locateOnScreen('foo.png') print('image found') except pyautogui.ImageNotFoundException: print('ImageNotFoundException: image not found')
- これはちょっと認識違いかも?(pyscreezeではなくpuautogui側のImageNotFoundExceptionを使うべき)
pyautogui の内部で使われている pyscreeze が2度仕様変更しましたが、pyautogui が2度目の仕様変更に追従していないようです。
PC内のフォントファイルのURLを全取得する
- 前提としてSandBoxをOFFにしておくこと
struct URLManager { /// 検索対象となるFontsディレクトリ static private var fontsDirectories: [URL] { guard let directoryInSystem = FileManager.default.urls(for: .libraryDirectory, in: .systemDomainMask).first?.appendingPathComponent("Fonts"), let directoryInGlobal = FileManager.default.urls(for: .libraryDirectory, in: .localDomainMask).first?.appendingPathComponent("Fonts"), let directoryInUser = FileManager.default.urls(for: .libraryDirectory, in: .userDomainMask).first?.appendingPathComponent("Fonts") else { return [] } return [directoryInSystem, directoryInGlobal, directoryInUser] } /// 指定したディレクトリ内のフォントのfileURLを取得 static private func loadFonts(in directory: URL) -> [URL] { guard let enumerator = FileManager.default.enumerator( at: directory, includingPropertiesForKeys: [.isRegularFileKey], options: [.skipsHiddenFiles, .skipsPackageDescendants]) else { return [] } var fontURLs = [URL]() let extensions = ["otf", "ttf", "ttc"] for case let fileURL as URL in enumerator { if extensions.contains(fileURL.pathExtension) { fontURLs.append(fileURL) } fontURLs.append(fileURL) } return fontURLs } /// 検索対象となるFontsディレクトリ内の全フォントのURLを取得 static func loadAllFontsInLocal() -> [URL] { var urls: [URL] = [] fontsDirectories.forEach { directory in urls += loadFonts(in: directory) } urls.sort { $0.path() < $1.path() } // AtoZに並べ替え return urls } }


