頭と尻尾はくれてやる!

パソコンおやじのiPhoneアプリ・サイト作成・運営日記


動画から画像を切り出す時の処理時間を計測した

macOSで動画ファイルから画像を切り出す時にAVFoundationのAVAssetImageGeneratorクラスの
func generateCGImagesAsynchronously(forTimes requestedTimes: [NSValue], completionHandler handler: @escaping AVAssetImageGeneratorCompletionHandler)
を使っている。
この最初の引数に欲しい画像の時刻に相当する値の配列を渡せばまるっとまとめてcompetionHandlerでくれる。
長い動画に対して処理をするとそこそこの時間、Macが固まることになる!
描画のタイミングはないからNSProgressIndicatorを書き換えることもできない。
ユーザーからすると、ちゃんと処理は進んでいるんだろうか?と心配になってしまう。

なのでなんとか途中で描画のタイミングを作って少しずつ画像を作成していくという方法を考えた。
心配なのはどのくらい時間のロスが発生するんだろうか?ということだ。

ということで一定枚数ごとに分割して画像を作成したらどうなるかを計測してみた。

全部で35枚の動画を作成する処理をn枚ごとに行った。
5枚ごとなら7回のループでちょうどだけど、
10枚ごとなら4回のループになり、4回目は枚数が少ない。

XCTest(ユニットテスト)のmeasureというのを使うとデフォルトで10回処理してその平均などを出してくれる。

結果をグラフにするとこんな感じ。
処理時間の結果のグラフ

そりゃ、まあ1回(横軸が35のところ)が最速になるよな。これを基準にすると、、、

処理時間の結果の表

1枚ごとなら15%ほど余計に時間がかかるけど、progress indicatorを書き換えるのなら1枚ごとじゃなくてもいいだろう。
10枚ごとなら4%ほどのロスだがこれで時々進捗を描けるならこっちの方がいいかな。


NSProgressIndicator
↑NSProgressIndicator。描画タイミングなくても逐次書き換えてくれるようになったらいいのにな。SwiftUIに期待?!



macOS 10.15.5 Catalina
Xcode 11.5
Swift 5.2.4
スポンサーサイト






Number Formatter付きのNSTextFieldで入力を数値だけにする

人様が公開してるmacOSアプリのサンプルコードを眺めてたらNSTextFieldの設定画面に何やらNumber Formatterが接続されている、、、?

Xcodeのoutlet設定画面

でもなんだか表示が通常のと違って薄いし、どこのファイルにもそのようなoutletの宣言もない、、、?
これ何?と調べたところ、storyboardでNSTextFieldを追加する時にText Field with Number Formatterなんて選択肢もあったのだ(気付かなかったなあ)。

UI追加画面

↑これを選択してstoryboard上で設置する。
ところがText Fieldを選択してもinspector(Xcodeの右の方に出てくる詳細設定画面)には数値に関する設定画面がない、、、?
散々探した結果、storyboardやxibファイル選択時にXcodeのメイン画面の左の部品構成一覧のところで

パーツの構成画面

↑このようにText Fieldの下の階層にNumber Formatterとあるのでここをクリックすると

Number Formatterの設定画面

↑inspectorに設定画面が出てきた!


ここを設定すればtext fieldが数値しか受け付けない、とかできた。



macOS 10.15.4 Catalina
Xcode 11.5


Swiftのextensionで += 演算子を実装する

整数などでは
age += 1
といった記述はできるのにCGPointではなぜか実装されていない。
そんな時はextension使って自作できるのがSwiftの楽しいところ。

CGPointだと + の演算子を実装するのに
extension CGPoint {

static func + (left: CGPoint, right: CGPoint) -> CGPoint {
return CGPoint(x: left.x + right.x,
y: left.y + right.y)
}
}
//使う時は
let p1 = CGPoint(x: 1, y: 2)
let p2 = CGPoint(x: 3, y: 4)
let p = p1 + p2
このように記述できる。

しかし += 演算子の場合には
p += p1
↑このように左側のCGPointを書き換える必要がある。
こういう場合はmutatingキーワードを使うんだよな!と思ったけど違った。
static func += (lhs: inout CGPoint, rhs: CGPoint) {
lhs.x = lhs.x + rhs.x
lhs.y = lhs.y + rhs.y
}
↑このように左側のにinoutキーワード追加、returnなしでいいみたい。

また一つextensionの記述方法を知ったわ。


macOS 10.15.4 Catalina
Xcode 11.5
Swift 5.2.4


UIImageにもinit?(contentsOf: URL)が欲しいので自作する

最近は再利用しそうなコードはなるべくiOS/macOSでもどちらからでも動くように心がけている。
ファイルのパスから画像オブジェクトを作成するのにmacOSのNSImageには
init?(contentsOfFile: String)
init?(contentsOf: URL)
の二つがあるのに、iOSのUIImageにはなぜか
init?(contentsOfFile: String)
しかない。

SwiftだとファイルへのアクセスはStringよりもURLがいいな、と思ってるのでここはextensionで自作しておこうかと。

ところが
UIImage(contentsOfFile: )
を使って画像をロードするのにえらくはまってしまった。

ここでの引数はString型。
画像のファイルパスはURLで持ってたのでそれをStringに変換したい。
let path = url.absoluteString
↑これだと正しくロードできずimageはnilになる↓
let image = UIImage(contentsOfFile: path)!

↓このようにすると
let path = try! String(contentsOf: url)
以下のようなエラーが出てpathが取得できない。
"The file “xxx.png” couldn’t be opened because the text encoding of its contents can’t be determined."

Encodingがどうとかあるので
let path = try! String(contentsOf: url, encoding: .utf8)
などとしてもダメ、、、

ようやくたどり着いたのが
let path = url.path
あああ、そういうことかよ、、、

ということで作成したのがこちら。これはiOS専用。
#if os(iOS)
extension UIImage {
convenience init?(contentsOf url: URL) {
let filePath = url.toString
self.init(contentsOfFile: filePath)
}
}
#endif

なお、URLをStringに変換するためのtoStringも作っておいた。
extension URL {
var toString: String {
return self.path
}
}

おまけ。StringをURLに変換するのはこんなの↓
extension String {
var toURL: URL {
return URL(fileURLWithPath: self)
}
}
↑この変換方法もいくつかあってObjective-Cの頃にはまった記憶がある。


ともかく、これでiOS/macOSとも画像オブジェクト生成にcontentsOf: url でいけるようになった。

なお、画像生成するのにパスを指定してるのはDocumentsやCachesディレクトリ、またmacOSだとデスクトップなどへのアクセスで使うため。異なるケースだと変換方法も異なるのかも?



macOS 10.15.4 Catalina
Xcode 11.4.1
Swift 5.2.2



iOS/macOSのscroll viewの簡単なサンプルコード

iOSでもmacOSでもscroll viewにはいつも悩まされる。
なのでシンプルなサンプルコードを作って確認してた。

YamaguchiTatsuya/ScrollView: This project has iOS/macOS scroll view’s sample using storyboard (and code).
↑そのプロジェクトをGitHubにアップした。

基本はstoryboardで完結させたいが、scroll viewに載せる内容をコードで記述した場合もあるのでどちらの場合に何をどこに紐付け(Auto Layoutのconstraintの設定)すればいいのか?他のstoryboardの設定は?などをコード内にメモしてる。
SwiftUIは一切使っていません。


macOS 10.15.4 Catalina
Xcode 11.4.1
Swift 5.2.2




Copyright ©頭と尻尾はくれてやる!. Powered by FC2 Blog. Template by eriraha.