openURLがDeprecatedだったので、新方式に置き換える
iOS10からopenURLが非推奨になったので、新しいメソッドに置き換えました。
- 旧記法
UIApplication.shared.openURL(URL(string: "https://google.co.jp")!)
- 新記法
UIApplication.shared.open(URL(string: "https://google.co.jp")!, options: [:], completionHandler: nil)
completionHandler
は遷移完了or遷移失敗したタイミングで呼ばれます。
引数は遷移が成功したかどうかの結果がBoolで渡されます。
UIApplication.shared.open(URL(string: "https://google.co.jp")!, options: [:], completionHandler: { result in print(result) // → true })
下のように遷移失敗するとresultにfalseが入ります。
UIApplication.shared.open(URL(string: "hoge://")!, options: [:], completionHandler: { result in print(result) // → false })
optionsは現在UIApplicationOpenURLOptionUniversalLinksOnly
のみサポートされています。
trueを渡すと、UniversalLink以外開けなくなります。
デフォルト値はfalseです。
UIApplication.shared.open(URL(string: "https://google.co.jp")!, options: [ UIApplicationOpenURLOptionUniversalLinksOnly: NSNumber(value: true)], completionHandler: nil)
UIApplicationOpenURLOptionUniversalLinksOnlyにはBool値を直接渡す事もできました。
UIApplication.shared.open(URL(string: "https://google.co.jp")!, options: [ UIApplicationOpenURLOptionUniversalLinksOnly: true], completionHandler: nil)
オプション一覧は下URLに記載されています。
Swift Playgroundsを使ってみる
今更ながら、Swift Playgroundsをしっかりと使ってみました。
Swift Playgrounds とは
Swiftを簡単に実行できる環境です。
書いたコードがすぐに実行されるので、簡単なコードを試したい時などに向いています。
Playgroundを使ってみる
PlaygroundはGet started with a playground
から使う事ができます。
起動すると下のような画面になっています。
変数の定義やprint文の実行で右側に結果が表示されます。
printの結果は下にも表示されます。
右端の四角を押すことで変数の中身がコード上に表示されます。
Playgroundでグラフを描く
forやeachを使うとグラフを描画する事ができます。
複雑な形も描画可能です。
複数変数を定義すれば複数グラフを表示できます。
Value Historyを使えば実際の値を調べる事もできます。
様々なものを表示する
PlaygroundではViewの描画もできます。
Viewにラベルを追加する事もできます。
画像も表示する事ができます。
素材はhttp://flat-icon-design.com/の素材を利用させて頂きました。
画像の追加をするには、右上のボタンから左側のナビゲーターを表示します。
そこで表示されるResourcesに画像をドラッグすればPlayground中で使えるようになります。
【Swift】DateとDateComponentsの相互変換
Date → DateComponentsの変換とDateComponents → Dateの変換について調べてみました。
Date → DateComponents
下のようにCalendarを使うとDateComponentsを取得できます。
let date = Date() let components = Calendar.current.dateComponents(in: TimeZone.current, from: date) components.year // 2017 components.month // 8 components.day // 31
下のように、Dateの一部情報だけを使ってDateComponentsを作る事もできます。
let date = Date() let components = Calendar.current.dateComponents([.calendar, .year, .month, .day], from: date) components.year // 2017 components.hour // nil
DateComponents → Date
DateComponentsからDateは下の通りです。
DateComponentsのdateプロパティーを通してDateを取得します。
let components = DateComponents(calendar: Calendar.current, year: 2017, month: 9, day: 1) components.date // → 2017/9/1 00:00
Dateへの変換ですが、Calendarがセットされてないとnilになるので注意が必要です。
let components = DateComponents(year: 2017, month: 9, day: 1) components.date // → nil
Calendarさえセットしておけば、Dateには変換できます。
let components = DateComponents(calendar: Calendar.current) components.date // → 1/1/1 00:00
それとyearとyearForWeekOfYearという近い意味の、両方セットするとどうなるか確かめてみました。
試したところyearForWeekOfYearが優先されるようです。
let components = DateComponents(calendar: Calendar.current, year: 2017, yearForWeekOfYear: 2016) components.date // → 2016/01/01
【Swift, UIActionController】アクションシートで外側のビューを押された時のイベント
アクションシートで外側のビュー(下の灰色部分)を押された時のイベント周りについて調べてみました。
キャンセルボタンがある場合、外側のビューを押すとアクションシートは閉じます。
その際、キャンセルボタンが押された時と同じ処理が呼び出されます。
import UIKit class ViewController: UIViewController { override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) let c = UIAlertController(title: nil, message: "めっせーじ", preferredStyle: .actionSheet) c.addAction(UIAlertAction(title: "OK", style: .default, handler: nil)) c.addAction(UIAlertAction(title: "キャンセル", style: .cancel, handler: { action in print("cancelled") // → 外側のビューをタップ or キャンセルボタンタップでここが呼ばれる })) present(c, animated: true, completion: nil) } }
handlerにnilを渡しても、同じようにアクションシートは閉じます。
let c = UIAlertController(title: nil, message: "めっせーじ", preferredStyle: .actionSheet) c.addAction(UIAlertAction(title: "OK", style: .default, handler: nil)) c.addAction(UIAlertAction(title: "キャンセル", style: .cancel, handler: nil))
キャンセルボタンがない場合は、外側のビューを押してもアクションシートが消えなくなります。
let c = UIAlertController(title: nil, message: "めっせーじ", preferredStyle: .actionSheet) c.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
キャンセルボタンを2つセットしようとすると、下のようなエラーが出てアプリがクラッシュします。
UIAlertController can only have one action with a style of UIAlertActionStyleCancel
let c = UIAlertController(title: nil, message: "めっせーじ", preferredStyle: .actionSheet) c.addAction(UIAlertAction(title: "キャンセル1", style: .cancel, handler: nil)) c.addAction(UIAlertAction(title: "キャンセル2", style: .cancel, handler: nil))
アクションシートをアラートに置き換えても、同じようにエラーになります。
let c = UIAlertController(title: nil, message: "めっせーじ", preferredStyle: .alert) c.addAction(UIAlertAction(title: "キャンセル1", style: .cancel, handler: nil)) c.addAction(UIAlertAction(title: "キャンセル2", style: .cancel, handler: nil))
【iOS】Referencing Outlet Collectionで複数の要素をひとまとめ
Storyboardにある、Referencing Outlet Collectionというものを試してみました。
Referencing Outletsはいつも使うのですが、Referencing Outlet Collectionは触ったことがないので一度使ってみました。
最初にStoryboard上で複数のUILabelを配置します。
次にViewControllerにUILabelの配列を定義します。
配列なので、通常の@IBOutletと違いweakが付きません。
class ViewController: UIViewController { @IBOutlet var labels: [UILabel]! }
それをStoryboardのUILabelと紐付ければ設定完了です。
設定をしたら、実際にラベルの値を変える処理を書いてみました。
class ViewController: UIViewController { @IBOutlet var labels: [UILabel]! override func viewDidLoad() { labels.enumerated().forEach { $0.element.text = "\($0.offset)" } } }
実行したらラベルの値が変わってる事を確認できました。
それと、labelsの並び順は紐付け順になっていました。
【iOS】ナビゲーションバーの背景を画像にする
ナビゲーションバーの背景を画像にしてみました。
画像は下のフリー素材を使っています。
青色のざらざらした紙のテクスチャ素材 | Paper-co | 紙のテクスチャー素材を無料でダウンロードできるサイト
バーに背景画像を設定する方法は下の通りです。
titleTextAttributes
はタイトルの色を白くする為の設定です。
class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() navigationController?.navigationBar.setBackgroundImage(UIImage(named: "texture"), for: .default) navigationController?.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName : UIColor.white] } }
起動すると以下のようにバーの背景が代わります。
もし画像サイズが小さい場合は、画像をリピート描画をしてくれます。
下のように、UIImageをUIColorに変換した上でbarTintColor
に設定しても同様の結果になります。
class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() navigationController?.navigationBar.barTintColor = UIColor(patternImage: UIImage(named: "texture")!) } }
アプリ内の全てのナビゲーションバーの背景を変える場合は、以下のようにappearanceを使います。
ちなみにbarTintColor
で画像をセットしている時にSafariViewControllerを使うと'NSInternalInconsistencyException', reason: 'Only RGBA or White color spaces are supported in this situation.'
というエラーでクラッシュします。
SafariViewController以外でもエラーになるかもしれないので、できるだけsetBackgroundImage
を使う方が安全そうです。
import UIKit @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { UINavigationBar.appearance().barTintColor = UIColor(patternImage: UIImage(named: "texture")!) return true } }