Objective-CからSwiftにしたら処理が劇的に重くなった話
⇒ Arrayの扱いが変わってきたので一旦この記事は保留で全体を見直すことにしました。
絶賛まだ修正中ですが、「Assetsを表示するプログラムをSwiftにしてみる 」でいろいろと作業しながらSwiftの勉強をしていたのですが、自分のおもいつくままの方法でObjective-CからSwiftにしたら処理が耐えられないほど重くなってしまいました・・・・。
いろいろと原因追及をしながら考えてみたいなと思います。
・・・考えている途中のメモです。
解決したら解決方法を追記する予定ですが現在解決しておりませぬ。
コメント募集中?
そもそも未熟すぎるのが悪いというのは大目に見てください・・・orz
劇重になった問題の処理
問題のコード部分はAssetLibraryからデータを取り出して日付でソートするという部分です。
日付順に格納したかったのでソート処理をしてデータを格納しなおしてごにょごにょしてました。
そもそもがサンプルで作ったソースなので元々が良くないのかもしれませんが、Objective-Cでは数秒程度の処理がSwiftにすることで数分の処理へと変貌してしまいました。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
ALAssetsGroupType assetsGroupType = ALAssetsGroupAlbum | ALAssetsGroupEvent | ALAssetsGroupFaces | ALAssetsGroupSavedPhotos;
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"yyyy/MM/dd"];
// アセットライブラリから取得したグループ内のアセットごとの処理
ALAssetsGroupEnumerationResultsBlock groupResultBlock = ^(ALAsset *asset, NSUInteger index, BOOL *stop) {
if (asset) {
NSDate *assetDate = [asset valueForProperty:ALAssetPropertyDate];
NSString *assetDateStr = [formatter stringFromDate:assetDate];
[allAssets addObject:@{ ASSET: asset, DATE: assetDate, DATE_STR: assetDateStr }];
}
};
NSComparator comparetor = ^NSComparisonResult (id obj1, id obj2) {
NSDate *datea = obj1[DATE];
NSDate *dateb = obj2[DATE];
return [dateb compare:datea];
};
// ライブラリからアセットグループを取得する処理
ALAssetsLibraryGroupsEnumerationResultsBlock resultBlock = ^(ALAssetsGroup *assetsGroup, BOOL *stop) {
// NSLog(@"AssetsGroup : %@", assetsGroup);
ALAssetsFilter *onlyPhotosFilter = [ALAssetsFilter allPhotos];
[assetsGroup setAssetsFilter:onlyPhotosFilter];
if (assetsGroup) {
if ([assetsGroup numberOfAssets] > 0) {
[assetsGroup enumerateAssetsUsingBlock:groupResultBlock];
}
} else {
// 全体sort
[allAssets sortWithOptions:NSSortConcurrent usingComparator:comparetor];
for (NSDictionary *asset in allAssets) {
NSString *dateStr = asset[DATE_STR];
if (self.assetsData[dateStr]) { // 存在していたら
[self.assetsData[dateStr] addObject:asset[ASSET]];
} else {
NSMutableArray *sectionArray = [[NSMutableArray alloc] init];
[sectionArray addObject:asset[ASSET]];
[self.assetsData setObject:sectionArray forKey:dateStr];
[sectionArray release];
[self.sectionList addObject:dateStr];
}
}
[formatter release];
[allAssets release];
[self.collectionView reloadData];
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
let assetsGroupType :ALAssetsGroupType! = ALAssetsGroupType(0xFFFFFFFF)
var fomatter = NSDateFormatter()
fomatter.dateFormat = "yyyy/MM/dd"
var groupResultBlock : ALAssetsGroupEnumerationResultsBlock = { (asset: ALAsset!, index: Int, stop:CMutablePointer<ObjCBool>) -> Void in
if asset {
let assetDate: NSDate = asset.valueForProperty(ALAssetPropertyDate) as NSDate
let assetDateStr: String = fomatter.stringFromDate(assetDate) as String
allAssets.append([self.ASSET:asset, self.DATE:assetDate, self.DATE_STR:assetDateStr])
}
}
var resultBlock : ALAssetsLibraryGroupsEnumerationResultsBlock = { (assetsGroup:ALAssetsGroup!, stop: CMutablePointer<ObjCBool>) -> Void in
let onlyPhotosFilter: ALAssetsFilter = ALAssetsFilter.allPhotos()
if assetsGroup {
assetsGroup.setAssetsFilter( onlyPhotosFilter )
if assetsGroup.numberOfAssets() > 0 {
assetsGroup.enumerateAssetsUsingBlock(groupResultBlock)
}
} else {
sort( allAssets ){ $0[self.DATE_STR] as String > $1[self.DATE_STR] as String }
for anAsset: Dictionary<Int,AnyObject> in allAssets {
let assetDict: NSDictionary = anAsset
let dateStr: String! = assetDict[self.DATE_STR] as String
if self.assetsData[dateStr] {
var asstsArr:Array<ALAsset> = self.assetsData[dateStr]!
asstsArr.append(anAsset[self.ASSET] as ALAsset)
self.assetsData[dateStr] = asstsArr
} else {
var sectionArray:Array<ALAsset> = []
sectionArray.append(anAsset[self.ASSET] as ALAsset)
self.assetsData[dateStr] = sectionArray
self.sectionList.append(dateStr)
}
}
self.collectionView!.reloadData()
}
}
Swiftにうまく変換できなかった部分は思いつくままに無理矢理やっている部分があります。
処理としては下記のものになります。
allAssets
という配列にまずはAssets
たちを全部入れていく
allAssets
を日付でソートする
ソートした結果をCollectionViewで使いやすいようにself.assetsData
へ日付をkeyにしたDictionaryに格納していく
以上の作業をしています。
細かくみていきたいと思います。
第1の問題点 : ALAssetsGroupType
AssetsLibraryからデータを取り出す時にALAssetsGroupType
を指定することで必要なデータのみ表示されるように調整しています。
1
ALAssetsGroupType assetsGroupType = ALAssetsGroupAlbum | ALAssetsGroupEvent | ALAssetsGroupFaces | ALAssetsGroupSavedPhotos;
1
let assetsGroupType :ALAssetsGroupType! = ALAssetsGroupType(0xFFFFFFFF)
実はここで問題が起きてしまいました。
AssetsLibraryを利用するので
を記載しています。が、ALAssetsGroupAlbum
が呼び出せないのです。
ヘッダファイルに飛んでみると、Objective-Cではenumで記述されていた部分が、変数の宣言に切り替わっています。
しかも、ALAssetsGroupType
はInt
型ですが、ObjCで宣言されていたALAssetsGroupAlbum
などはCUnsignedInt
型です。
そしてALAssetsGroupType
はtypealias
で宣言されています。
1
2
3
4
5
6
7
8
9
10
11
var ALAssetsGroupLibrary: CUnsignedInt { get } // The Library group that includes all assets.
var ALAssetsGroupAlbum: CUnsignedInt { get } // All the albums synced from iTunes or created on the device.
var ALAssetsGroupEvent: CUnsignedInt { get } // All the events synced from iTunes.
var ALAssetsGroupFaces: CUnsignedInt { get } // All the faces albums synced from iTunes.
var ALAssetsGroupSavedPhotos: CUnsignedInt { get } // The Saved Photos album.
var ALAssetsGroupPhotoStream: CUnsignedInt { get } // The PhotoStream album.
var ALAssetsGroupAll: CUnsignedInt { get } // The same as ORing together all the available group types,
typealias ALAssetsGroupType = Int
この子たちの扱いがわかりません・・・。
いろいろ試行錯誤して下記の書き方にしてみました。
1
let assetsGroupType :ALAssetsGroupType! = ALAssetsGroupType(ALAssetsGroupAll)
こうするとこの行でXcodeが落ちてしまいますorz
うーん。まだ勉強不足故このあたりをどう書けばいいのかわからず、結局0xFFFFFFFF
と直に書いて進むことにしてしまいました。
絶賛解決方法探し中。
ちなみにplaygroundでは
1
Playground execution failed: error: <REPL>:60:1: error: use of unresolved identifier 'ALAssetsGroupAll'
と、表示されています・・・。importが間違えてるのかなぁ・・・。
第2の問題点 : sort
ObjCではNSComparator
を使ってた部分をSwiftではsort
があるのでそれを使いました。
allAssetsには
1
2
3
4
5
6
7
NSComparator comparetor = ^NSComparisonResult (id obj1, id obj2) {
NSDate *datea = obj1[DATE];
NSDate *dateb = obj2[DATE];
return [dateb compare:datea];
};
[allAssets sortWithOptions:NSSortConcurrent usingComparator:comparetor];
1
sort( allAssets ){ $0[self.DATE_STR] as String > $1[self.DATE_STR] as String }
参考