2017年03月21日

[Swift2]NSCalendarUnitの合成


NSDateから年・月・日などの数字だけを抜き出すときにNSDateComonentsを使うんだけど、Swiftでちょっと書き方が変わった部分がある。

Objective-C時代はこんな書き方でした。リファレンスからの抜粋。


unsigned unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit;
NSDate *date = [NSDate date];
NSDateComponents *comps = [gregorian components:unitFlags fromDate:date];


これがSiwft2では以下のようになるとリファレンスには書かれている。これだとObjective-Cとさほど代わりはない。


let flags: NSCalendarUnit = .DayCalendarUnit | .MonthCalendarUnit | .YearCalendarUnit
let date = NSDate()
let components = gregorian.components(flags, fromDate: date)


ところがこれを Xcode 7.2.1 で書くと、エラーになってしまってコンパイルできない。


Type of expression is ambiguous without more context


型が分からないというなら直接的に指定するしかないと指定する。


let flags2: NSCalendarUnit = NSCalendarUnit.Day | NSCalendarUnit.Month | NSCalendarUnit.Year


が、するとまた別のエラーになる。


Binary operator '|' cannot be applied to two 'NSCalendarUnit' operands'



じゃあ、一体どう指定するんだよ?と強引に指定するとこんな風になる。


let calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)
let flags = NSCalendarUnit(rawValue: NSCalendarUnit.Year.rawValue
+ NSCalendarUnit.Month.rawValue
+ NSCalendarUnit.Day.rawValue
)
guard let comps = calendar?.components(flags, fromDate: date) else {
return
}
let year = comps.year, month = comps.month, day = comps.day


確かにこれだと正常に実行できるんだけど、あまりにも強引すぎてもっときれいな書き方があっていいはずなんだけど。

Swift3ではこんな書き方になる(クラス名等はSwift2のまま)。


let calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)
guard let comps = calendar?.components([.Year,.Month,.Day], fromDate: date) else {
return
}


そしてこれがまたコンパイルが通って正常に実行される。Swift3ではメソッドがSetで定義されているのでこれでもいいのだが、Swift2ではcomponents(flags:NSCalendarUnit, fromDate: NSDate)とNSCalendarUnitで定義されているので[NSCalendarUnit]で渡して渡せる理由がわからない。

そこでこんな書き方をしてみたら、ようやくなぜだかわかった。


let calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)
let flags = NSCalendarUnit([.Year,.Month,.Day])
guard let comps = calendar?.components(flags, fromDate: date) else {
return
}


リファレンスとかからはわからないけどNSCalendarUnitのコンストラクタに配列を取るものがあるってことなんでしょう。

posted by 永遠製作所 at 15:16| 東京 ☔| Comment(0) | TrackBack(0) | Swift | このブログの読者になる | 更新情報をチェックする

2017年03月20日

[macOS, Swift2] ファイル選択ダイアログ

未だに古い環境のOS Xでプログラミングしてるんだけど、その中の基本的な操作であるファイルオープンダイアログの使い方を一応覚え書きとして。

NSOpenPanelはObjective-C時代そのまま。インスタンスはそのままコンストラクタで作る。シートでダイアログを開いて、結果はブロックで受け取る。OK/Cancelは NSFileHandlingPanelOKButton / NSFileHandlingPanelCancelButton で判定。

以下はNSViewControllerのサブクラス中で使う場合。


func showOpenPanel() {
let panel = NSOpenPanel()
panel.beginSheetModalForWindow(self.view.window!) {
[weak self] (response) -> Void in

switch ( response ) {
case NSFileHandlingPanelOKButton:
let urls = panel.URLs
self?.readFromURL(urls[0])
break
default:
return
}
}
}


シートを表示している最中だからselfがなくなることはないと思うけど、一応ブロック中でselfを使う場合は習慣化させたいので weak self 。

ファイルを1つだけ選択する場合。NSURLで受け取るのが現代的。複数選択する場合やディレクトリ可の場合には beginSheet... の前に下記コードを入れておくだけ。


self.allowsMultipleSelection = true
self.canChooseDirectories = true


posted by 永遠製作所 at 00:07| 東京 ☀| Comment(0) | TrackBack(0) | Swift | このブログの読者になる | 更新情報をチェックする

2017年02月24日

『iOS 7デザインスタンダード』

iOS 7デザインスタンダード 最新のフラットデザインに対応-iPhoneに最適なUI・UXを徹底的に解説!
荻野 博章



2013年11月発売の本。タイトル通りiOS 7になって大幅変更になったデザインについて書かれている。発売直後に買ったのだけど、今頃になってようやく読んだ。

それまでのiOSアプリケーションでは、アイコンにしろUIにしろ現実に存在するもののメタファーとして立体感のあるデザインを採用していた。これがiOS 7からは、フラットデザインと呼ばれるまったく違った物に変更となった。

本書ではフラットデザインがどのようなものなのかを新旧のデザインを比較しながら、わかりやすく説明している。基本コンセプトとして「服従(Deference)」「明瞭(Clarity)」「重層(Depth)」を示し解説も細やか。
続きを読む
posted by 永遠製作所 at 23:28| 東京 ☁| Comment(0) | TrackBack(0) | iPhone/iPod touch | このブログの読者になる | 更新情報をチェックする

2016年11月07日

WWDC14 | Session 208 | Introducing CloudKit - Frameworks

WWDC14 | Session 208 | Introducing CloudKit - Frameworks
54:45
https://developer.apple.com/videos/play/wwdc2014/208/

※WWDCセッション関係の記事は、セッション内容を要約して内容を伝えるのが目的ではない。各セッションビデオで何が話されているかの項目をテキスト化することで後で何かを調べたいときにどのビデオを見れば良いか判断する材料にするために書いている。

iOS 8から新たに導入された CloudKit に関する概要を述べるセッション。主要なクラスの使い方なども紹介する。

続きを読む
タグ:WWDC CloudKit
posted by 永遠製作所 at 01:12| 東京 ☀| Comment(0) | TrackBack(0) | WWDC | このブログの読者になる | 更新情報をチェックする

2016年08月28日

iOSシミュレータのデータフォルダ


Xcode7からだろうか?シミュレータで実行した時のデータを保存するフォルダの位置が変わった。

/Users/【ユーザ名】/Library/Developer/CoreSimulator/Devices/【シミュレータデバイスID】/data/Containers/Data/Application/【アプリID】/Documents

【シミュレータデバイスID】、【アプリID】はそれぞれ任意のUUIDが付されるのでなかなか人間がその文字列を見てiPhone6sのフォルダだなと、今開発中のアプリのIDがこれだなと判断するのは難しい。

例えば「4C939428-F8A9-4460-9C30-16D1F8896224」のような文字列になる。

デバイス名はUUIDのフォルダ名の下の「device.plist」中に書かれている。

【ユーザ名】が john とすると例えば下記のようになる。
/Users/john/Library/Developer/CoreSimulator/Devices/4C939428-F8A9-4460-9C30-16D1F8896224/data/Containers/Data/Application/0C73FCD2-16C2-4E96-A3E5-E3A0EF755D88/Documents

ユーザー毎の「ライブラリ」フォルダはこれもいつのころからだったか(Marvericsかな?)不可視ファイルとなっているのでフォルダに移動するには、「ファインダ>移動>フォルダへ移動…」やターミナルから開くなどの方法が必要。

アプリケーション名はバンドルフォルダのほうを見る必要がある。

/Users/【ユーザ名】/Library/Developer/CoreSimulator/Devices/【シミュレータデバイスID】/data/Containers/Bundle/Application/【アプリID】/【アプリ名】.app

各国語のアプリケーション名を知りたければアプリケーションバンドルの中のInfoPlist.stringsを見る。

/Users/【ユーザ名】/Library/Developer/CoreSimulator/Devices/【シミュレータデバイスID】/data/Containers/Bundle/Application/【アプリID】/【アプリ名】.app/【言語ID】.lproj/InfoPlist.strings

データフォルダではなく、一時保存ファイルはtmpフォルダにある。

/Users/【ユーザ名】/Library/Developer/CoreSimulator/Devices/【シミュレータデバイスID】/data/Containers/Data/Application/【アプリID】/Documents

/Users/【ユーザ名】/Library/Developer/CoreSimulator/Devices/【シミュレータデバイスID】/data/Containers/Data/Application/【アプリID】/tmp/
posted by 永遠製作所 at 15:12| 東京 ☀| Comment(0) | TrackBack(0) | iPhone/iPod touch | このブログの読者になる | 更新情報をチェックする