- 投稿日:2019-11-25T23:06:43+09:00
メモ
可変である上のlabelのオートレイアウトはwide上下左右に付与
下のlabelはwide高さ左右に付与
下のオートレイアウト は付与しない全体のコード
func view() { let view1 = CustomView.init(frame: CGRect(x: 0, y: 0, width: 200, height: 591)) view1.test.text = "あああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああ" // view1.test.sizeToFit() let height = view1.test.sizeThatFits(CGSize(width: view1.test.frame.size.width, height: CGFloat.greatestFiniteMagnitude)).height view1.test.heightAnchor.constraint(equalToConstant: height).isActive = true view.addSubview(view1)
- 投稿日:2019-11-25T22:42:59+09:00
RxSwiftでAPIを複数呼ぶよ
Firestoreで参照使ってガッチャンコさせてました。
struct A { let id: String let name: String let bIDs: [String] } struct B { let id: String let name: String } func getA() -> Single<A> {...} func getB(id: String) -> Single<B> {...}みたいなとき?のように
toArray()
を駆使することで比較的シンプルにかけるみたい。func getBList() -> Single<[B]> { return getA().flatMap({ (a: A) -> Single<[B]> in Observable.from(a.bIDs) .flatMap({ (id: String) -> Single<B> in getB(id: id) }).toArray() }) }Bの順序を保ちたい場合は
concatMap
を使えば良さげ。最初にsubscribeをネストさせていたのはナイショ?
最近、RxSwift書き始めたのでもっとこう書くべきってのがあったら指摘ください..!
- 投稿日:2019-11-25T22:29:35+09:00
[はじめてのiOSアプリ]xcodeで地図アプリを作成(その2)
はじめに
iOSアプリを作ってみたいけど
何から始めて良いのかわからないとりあえず、
「やってみました」記事を参考に
地図アプリを真似てみようと思うという記事の2回目です。
今回は、地図を表示します。
地図を表示
- MapKit.framework を追加
- Mapkit を画面に配置
- 画面左側のファイルツリーから[Main storyboard]を選択
![]()
- 【なぜ?】
- あとで[Main storyboard]にGUIの地図部品を配置したいから、まずは選択しておく
- [Main storyboard]を編集することで表示内容を決定できる
- メニューから[View]-[Show Library]を選択、表示されるウインドウで [map] と入力し [Map Kit View]を絞り込む
![]()
- 【なぜ?】
- [Map Kit View]は地図を表示するためのGUI部品
- 今回は、機能と名称が一致しているので絞り込みが楽々!
- 絞り込み表示された[Map Kit View]を、Xcode右画面に表示される iPhone 画面上に、ドラッグ&ドロップする
![]()
- 【なぜ?】
- [Map Kit View]を[Main storyboard]に配置することで地図が表示できる
- [Map Kit View]を画面いっぱいに配置
- テスト実行
今回の到達点
- シミュレーターを使って地図を表示できた
連載
- 投稿日:2019-11-25T16:43:56+09:00
Combineでよく見るSwiftのNever型とは
Never let me go — けして私を離さないで、僕たちはけしてと言うけれどその約束を守るのは難しい。
でも僕たちの愛する Swift ではNever
は絶対的なNever
でその単純さが美しかった。まぁそんなポエムはいいんですけど、iOS13から導入された Combine ではよく
Never
という型を見る。@Published var x = 0 @Published var y = 0 var timesPublisher: AnyPublisher<Int, Never> { $x.combineLatest($y) .map(*) .eraseToAnyPublisher() }
AnyPublisher<Int, Never>
と失敗したときの型がNever
になっている。これはけして失敗しないことを型で表現してる。
Publisher
protocol の定義を見てみると publisher は失敗した場合の型を指定する必要がある。例え失敗しない場合でも型を指定する必要があるので失敗しないということを表すNever
がここで必要になってくる。public protocol Publisher { /// The kind of values published by this publisher. associatedtype Output /// The kind of errors this publisher might publish. /// /// Use `Never` if this `Publisher` does not publish errors. associatedtype Failure : Error /// This function is called to attach the specified `Subscriber` to this `Publisher` by `subscribe(_:)` /// /// - SeeAlso: `subscribe(_:)` /// - Parameters: /// - subscriber: The subscriber to attach to this `Publisher`. /// once attached it can begin to receive values. func receive<S>(subscriber: S) where S : Subscriber, Self.Failure == S.Failure, Self.Output == S.Input }Uninhabited Types
Never
という型がどういうものなのか関数を作ってみていく。型の宣言だけした関数を用意してみるとエラーで
Int
を返す関数はInt
を返してないと言われるのに対してNever
を返す関数のエラーは何やらいつものエラーと違うものになってる。Function with uninhabited return type 'Never' is missing call to another never-returning function on all paths
uninhabited return type 'Never' というよくわからない説明をされる。
どうやらNever
というのは普通の型とは違うらしい。ここで
Never
の定義を見てみる。public enum Never {}普通の enum の定義だがそこには
case
が一つもなかった。
enum は init を持たないのでcase
がないということは値を作ることができないということになる。このように値を作れない型のことを uninhabited type という。
しかし値を作れない型が何の役に立つんだと思うかもしれない。
プログラムを書いてると値を返さない関数(無限ループ、プログラムの終了)を書きたくなることがある。Never
があればそのような関数の型を正しく表現することができるようになる。でも、値を返さない関数の時は
Void
で定義するじゃんと普通思う。そこで Swift での
Void
が何なのか定義をみてみる。public typealias Void = ()Swift での
Void
は空のタプルの別名として定義されている。
そして Swift で関数定義する時に戻り値の型を定義しなかったら常に戻り値の型はVoid
になる。func log(_ message: String) { print("Message: \(message)") } let logger: (String) -> Void = log logger("This is void function")空のタプルは
()
という型でありlet unit = ()
として値を作ることができる。
このようにただ一つしか値がない型をユニット型という。なので()
の型や値のことをユニットとよく呼ぶ。つまり Swift での値を返さない関数と思っていた
-> Void
な関数は実際にはユニットを返してるのと同じ関数になる。func f() -> Void {} func g() { return () }
print()
のように値を返さないと思っている関数は実は値を返している。let printResult: Void = print("This is void function") print(printResult) // => ()NeverとVoidの関数の違い
値を返さない無限ループの関数を作ってみる。
func giveMeNever() -> Never { while true {} }この値を返さない関数を値を返す関数の中で呼んでみる。
func giveMeNever() -> Never { while true {} } func giveMeInt() -> Int { giveMeNever() }
giveMeInt()
はInt
の値を返してないけどエラーなくコンパイルすることができる。
giveMeNever()
の代わりにVoid
を返す関数を呼んでみる。Cannot convert return expression of type '()' to return type 'Int'
()
はInt
に変換できないとエラーになった。
Swift は強い型づけされた言語なので変換できないと言われる、なのに-> Never
をInt
を返すところで呼んでもエラーにならない。Never
だけ特別扱いなのだろうか?まるでNever
がInt
として扱われてるみたいだ。他の型でもいいのだろうか?Double
は?String
は?func giveMeDouble() -> Double { giveMeNever() } func giveMeString() -> String { giveMeNever() }エラーにならなかった。このコードは Swift では許可されたコードになる。
まるでNever
はInt
でもあるしDouble
,String
でもあるようだ。
Never
のように値を作ることができなくて、すべての型のサブ型のことを型理論ではボトム型という。ボトム型
ボトム、底、底があるならこの世にはその逆の上の世界があると人は夢をみる。
型の世界にもボトムがあるようにトップがある。ボトム型が全ての型のサブ型ならトップ型はその逆の全てのサブ型はトップ型のサブ型であるとなる。
Swift には
Any
という型がある。
Any
はあらゆる型の値を表すことができる型だ。例え関数でもだ。func anyWeSayAnyType(_ x: Int) -> Any { switch x { case 4: return 12 case 3: return 12.34 case 2: return true case 1: return "This is String type but it's also Any" default: return { (x: Int, y: Int) in x * y } } }
Any
のようにあらゆる型の値を表せるのをトップ型という。
その逆のボトム型はあらゆる型のサブ型なのでInt
でもDouble
でもString
としても扱える。ボトム型のようでボトムじゃない Never
まるで
Never
はInt
でもあるしDouble
,String
でもあるようだ。と前に言った。本当にそうなのだろうか?
コードで確かめてみよう。
Never
は定義した型に変換できないとエラーになる。
しかしクロージャで包んであげるとエラーにはならない。func isNeverBottomType() { let x: Int = { giveMeNever() }() let flag: Bool = { giveMeNever() }() let text: String = { giveMeNever() }() }このように Swift 5.1 では
Never
は本物のボトム型ではない。
Never
のような uninhabited type を関数の戻り値とする場合だけボトム型のような振る舞いをする。一応 Swift の設計者は
Never
を Swift 3 で導入した時にボトム型にすることを提案はしていた。
Never as a universal "bottom" subtypeNeverによって得た型の表現力
Swift では
fatalError()
という関数をよくみる。致命的なエラーだからプログラムを終了するという関数だ。定義を見てみる。
public func fatalError(_ message: @autoclosure () -> String = String(), file: StaticString = #file, line: UInt = #line) -> Never
Never
を返してる。
しかしfatalError()
は Swift 3以前は定義が違った。大体こんな定義だった。@noreturn func fatalError(_ message: () -> String = String(), file: StaticString = #file, line: UInt = #line)
Never
の代わりに@noreturn
という注釈がつけられている。これはコンパイラにこの関数は戻り値がないということを教えている。
基本的にはNever
が使われてる意図と同じだ。しかし
@noreturn
にはいくつか問題点があった。
次のような使い方をしたらどうなるだろうか?@noreturn func square(_ x: Int) -> Int { ... } @noreturn func runApp() throws { ... }値を返す関数やエラーを投げる関数に
@noreturn
をつけたらどうすればいいだろうか?
コンパイラは最初の値を返す場合はエラーにしたらいいだろう、でもエラーを投げる場合は許可すべきだろうか?許可はするけど値は返さないとすればいいだろうか?それとも値を返さないしエラーを投げることもないとすればいいだろうか?明らかな正解はない。
注釈による戻り値がないことを表すとこのように複雑性が生まれる。Swift はこの問題を
Never
を導入することによって解決した。
Never
という値を作れない型で値を返せないことを型として表現した。とても単純で美しい解決方法だ。おわりに
ここまで読んでくださってありがとうございます。
Never
というとても小さく単純な型をみてきた。
小さく単純なものを定義することによってプログラミングでよくある問題を表現することができるのは美しいと思う。Never return Never
- 投稿日:2019-11-25T00:13:33+09:00
SwiftUIでtabItemの画像サイズを変更する方法
SwiftUI tips
SwiftUIでタブのアイテムのサイズを変更するのに少し苦戦したので共有します。
なお、大きくしたアイコンがtabの一番上に付いていてpaddingも効かないのでご了承?♂️
(解決策あったら米キボンヌ)成功するパターン
Text("user") .tabItem { Image(systemName: "person") .font(.title) } .tag(4)ダメなパターン
Text("user") .tabItem { Image(systemName: "person") .resizable() .aspectRatio(contentMode: .fit) .frame(width: tabItemSize, height: tabItemSize) } .tag(4)参考URL
- 投稿日:2019-11-25T00:13:33+09:00
SwiftUIでtabItemのSF Symbolsのサイズを変更する方法
SwiftUI tips
SwiftUIでタブのアイテムのサイズを変更するのに少し苦戦したので共有します。
なお、大きくしたアイコンがtabの一番上に付いていてpaddingも効かないのでご了承?♂️
(解決策あったら米キボンヌ)成功するパターン
Text("user") .tabItem { Image(systemName: "person") .font(.title) } .tag(4).font(.system(size: 10))//とかでも行けるダメなパターン
Text("user") .tabItem { Image(systemName: "person") .resizable() .aspectRatio(contentMode: .fit) .frame(width: tabItemSize, height: tabItemSize) } .tag(4)参考URL
- 投稿日:2019-11-25T00:11:40+09:00
Swift5.1のattribute全解説(全27種)
概要
Swift5.1で利用できるattributeの一覧です。(Public APIのみ)
本記事は以前作成したSwiftのattributeまとめ[Swift4対応]をSwift5.1向けに更新したものです。
attributeは全てを暗記する必要はありません。これなんだっけ、と思ったときにこの記事でさくっと見られる簡易リファレンスになればと思います。
attributeとは
- コンパイラに対し、宣言や型の補足情報を伝えるもの
- 属性や修飾子とも呼ばれる
- Swift5.1では公式リファレンスに記載されているもので全27種類
attributeの記法
- attributeの記法は以下のようになり、より詳細な情報を補足するために引数も指定することができる
- @〜という記法はコンパイラディレクティブと呼ばれ、コンパイラに対する指示を記載する際に利用される
// 引数なしの場合 @属性名 // 引数ありの場合 @属性名(引数)attribute一覧
- autoclosure
- escaping
- convention
- available
- discardableResult
- objc
- nonobjc
- objcMembers
- GKInspectable
- UIApplicationMain
- NSApplicationMain
- NSCopying
- NSManaged
- testable
- IBAction
- IBOutlet
- IBDesignable
- IBInspectable
- dynamicCallable
- dynamicMemberLookup
- frozen
- inlinable
- usableFromInline
- propertyWrapper
- requires_stored_property_inits
- warn_unqualified_access
- unknown
※ドキュメントに記載のあるPublic APIのみです。
@autoclosure
- 以下のように、呼び出し部分で引数として渡した値を、メソッド(関数)内ではクロージャーとして扱える
- クロージャーとして渡しているため、引数が実際に評価されるのは、クロージャーの実行時(遅延評価が可能)
例// 定義部分 func someMethod(closure: @autoclosure () -> Int) { print(closure()) } // 呼び出し部分 someMethod(closure: 10)利用シーンは少ないと想定するが、&&演算子や||演算子の実装などで利用
&&演算子、||演算子の実装public static func &&(lhs: Bool, rhs: @autoclosure () throws -> Bool) rethrows -> Bool public static func ||(lhs: Bool, rhs: @autoclosure () throws -> Bool) rethrows -> Bool
@escaping
- クロージャをスコープ外でも保持する必要があることを示す
- 以下の例では、completionクロージャーの実行を非同期で実行しているため、スコープ外ではクロージャーが保持されず、コンパイルエラー
例// NG: コンパイルエラー func someAsyncMethod(completion: () -> Void) { DispatchQueue.main.async { completion() } } // OK func someAsyncMethod(completion: @escaping () -> Void) { DispatchQueue.main.async { completion() } }
@convention
- 関数のポインタに対し、その呼び出し方式を指定
例// Swiftの関数ポインタ(デフォルト) var swiftFunction: @convention(swift) (Bool) -> Bool // Objective-Cと互換性をもつブロックポインタ var block: @convention(block) (Bool) -> Bool // C言語の関数ポインタ var cFunction: @convention(c) (Bool) -> Bool
@available
- 各OSバージョンなどの環境に対し、APIの有効性を表す
- Swiftのバージョン(swift)
- プラットフォームの種類(iOS,iOSApplicationExtension, macOS, macOSApplicationExtension, watchOS, watchOSApplicationExtension ,tvOS, tvOSApplicationExtension)
例// 全環境(*)で利用不可(unavailable)、SomeProtocolにリネームした(renamed:) @available(*, unavailable, renamed: "SomeProtocol") protocol MyProtocol { ... } // macOS 10.12で廃止(obsoleted)とメッセージを表示(message) @available(macOS 10.12, obsoleted: 10.12, message: "macOS 10.12で廃止されました") func someMethod() { ... } // iOS2で導入(introduced)、iOS9で非推奨(deprecated) @available(iOS, introduced: 2.0, deprecated: 9.0) var some: String例えば、iOS9で非推奨となった、UIAlertViewは以下のようにattribute指定することで、UIAlertViewを利用した際にコンパイラ警告を出し、UIAlertControllerの利用を推奨する。
UIAlertView.h@available(iOS, introduced: 2.0, deprecated: 9.0, message: "UIAlertView is deprecated. Use UIAlertController with a preferredStyle of UIAlertControllerStyleAlert instead") open class UIAlertView : UIView { ... }
@discardableResult
- 返り値を持つ関数やメソッドの返り値を利用しなかった場合のコンパイラ警告を無視する
- 返り値を必ずしも利用しなくて良いメソッドを定義するのに適する
例// メソッドの定義部分 func someMethod1() -> Bool { ... } @discardableResult func someMethod2() -> Bool { ... } // 呼び出し部分 someMethod1() // NG:メソッドの返り値を利用していないためコンパイラ警告がでる someMethod2() // OK
@discardableResult
を指定しない場合は「Result of call to 'someMethod()' is unused」とwarningが表示される。
@objc
- Objective-Cから使用できることを明示的に宣言
- extensionに指定すると全てのメンバに一括で指定できる
@objc(引数)
でObjective-Cで使いたい名前を指定できる- Swift4以前ではNSObjectを継承したクラスやdynamicでは暗黙的に
@objc
が付け加えられていましたが、Swift4では付与されなくなりました(Proposal: SE-0160)例// someMethodとしてObjective-Cから利用可能 @objc(someMethod) func someMethodForObjc() { ... }
@nonobjc
- Objective-Cから使用できないことを明示的に宣言
- extensionに指定すると全てのメンバに一括で指定できる
例@nonobjc func SomeMethodForSwift() { ... }
@objcMembers
- クラス全体に対し一括でObjective-Cから使用できることを明示的に宣言
- @objcMembersを付与したクラスのサブクラスやエクステンションにも影響
- Swift4で導入(Proposal: SE-0160)
例@objcMembers class MyClass : NSObject { // @objcになる func foo() { } // @objcにならない(タプルを返しているため) func bar() -> (Int, Int) { return (1, 1) } } extension MyClass { // @objcになる func baz() { } } class MySubClass : MyClass { // @objcになる func wibble() { } } extension MySubClass { // @objcになる func wobble() { } }
@GKInspectable
- カスタムのGameplayKitコンポーネントプロパティをSpriteKitエディタのUIに公開する
- 暗黙的に
@objc
が付け加えられる例class MyComponent: GKComponent { @GKInspectable var speed: Float = 1.0 @GKInspectable var friction: Float = 2.0 }
@UIApplicationMain
- アプリケーションデリゲートであることを示す(iOSアプリ用)
- この属性がない場合はmain.swiftを用意し、UIApplicationMain(::_:)関数を利用してデリゲート設定を行う
例(AppDelegate.swift)import UIKit @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { return true } func applicationWillResignActive(_ application: UIApplication) { } func applicationDidEnterBackground(_ application: UIApplication) { } func applicationWillEnterForeground(_ application: UIApplication) { } func applicationDidBecomeActive(_ application: UIApplication) { } func applicationWillTerminate(_ application: UIApplication) { } }
@NSApplicationMain
- アプリケーションデリゲートであることを示す(macアプリ用)
- この属性がない場合はmain.swiftを用意し、UIApplicationMain(::_:)関数を利用してデリゲート設定を行う
例(AppDelegate.swift)import Cocoa @NSApplicationMain class AppDelegate: NSObject, NSApplicationDelegate { func applicationDidFinishLaunching(_ aNotification: Notification) { } func applicationWillTerminate(_ aNotification: Notification) { } }
@NSCopying
- ストアドプロパティのセッターでコピーした値をセットする
- Objective-Cのcopy属性と同様
- Swift4でイニシャライザでの挙動が改善されました(Proposal: SE-0153)
例@NSCopying var foo: Foo
@NSManaged
- クラスのインスタンスメソッドやストアドプロパティに対し、CoreDataで実行時に動的に実装が生成されることを宣言する
例@NSManaged var name: String
@testable
- モジュールのimport宣言に対し、internal以上のアクセスレベルで公開されているメソッドやプロパティに対しテストクラスがアクセス可能なことを宣言する
例@testable import SomeModule
@IBAction
- メソッドがInterfaceBuilder(StoryBoard)に配置したパーツのアクションに紐付けられることを示す
- 暗黙的に
@objc
が付け加えられる例@IBAction func buttonTapped() { ... }
@IBOutlet
- プロパティがInterfaceBuilder(StoryBoard)に配置したパーツに紐づけられることを示す
- 暗黙的に
@objc
が付け加えられる例@IBOutlet weak var detailDescriptionLabel: UILabel!
@IBDesignable
- UIViewまたはNSViewを継承したカスタムクラスに指定するとデザインやサブビューがInterfaceBuilder(StoryBoard)上でライブレンダリングされる
- 暗黙的に
@objc
が付け加えられる例@IBDesignable class CustomView: UIView { ... }
@IBInspectable
- プロパティに指定すると、InterfaceBuilder(StoryBoard)のAttribute Inspectorで設定でき、ライブレンダリングでデザインを確認できる
- 対応する型(Int, CGFloat, Double, String, Bool, CGPoint, CGSize, CGRect, UIColor, UIImage)
- 暗黙的に
@objc
が付け加えられる例@IBInspectable public var cornerRadius: CGFloat = 2.0 { didSet { self.layer.cornerRadius = self.cornerRadius } }
@IBSegueAction
- StoryboardでSegueを設定し、画面遷移する際の処理を指定できる
- 引数のNSCoderインスタンスを利用し、遷移先のViewControllerの任意のイニシャライザを指定することが可能
例@IBSegueAction private func openDetail(coder: NSCoder, sender: Any?, segueIdentifier: String?) -> DetailViewController? { return DetailViewController(coder: coder, item: item) }
@dynamicCallable
- 型に
@dynamicCallable
を付与し、dynamicallyCall(withArguments:)
メソッドもしくはdynamicallyCall(withKeywordArgument:)
メソッドを実装することで、その型を関数のように直接呼び出しができるようになる例@dynamicCallable struct Sum { // 引数ラベルなし func dynamicallyCall(withArguments args: [Int]) -> Int { return args.reduce(0, +) } // 引数ラベルあり func dynamicallyCall(withKeywordArguments args: KeyValuePairs<String, Int>) -> Int { return args.map { $0.value }.reduce(0, +) } } let sum = Sum() print(sum(1, 2, 3)) // 6 print(sum(first: 1, second: 2, third: 3)) // 6
@dynamicMemberLookup
- 型に
@dynamicMemberLookup
を付与し、subscript(dynamicMember:)
を実装することで、コンパイル時に存在しないプロパティに.でアクセスが可能となる例@dynamicMemberLookup struct Dog { subscript(dynamicMember key: String) -> String { return key } subscript(dynamicMember key: Int) -> Int { return key } } let dog = Dog() print(dog.name) // "name" print(dog.1) // 1
@frozen
- library evolution mode(-enable-library-evolutionオプション)でコンパイル時のみ有効
- structもしくはenumに付与し、将来のバージョンでの型の変更を制限する
- structではストアドプロパティ、enumではcaseの追加、削除、並び替えを制限する
- library evolution modeでない場合には全てのstruct、enumが暗黙的に
@frozen
となる例@frozen enum IceCream { case vanilla case chocolate case greenTea }
@inlinable
- 関数、メソッド、コンピューテッドプロパティ、subscript、コンビニエンスイニシャライザ、デイニシャライザに付与することで、実装をmodule interfaceの一部として公開する(インライン展開)
- publicもしくはinternalで宣言されたものにのみ付与可能(実際にはinternalで定義された
@inlinable
は@usableFromInline
を意味する)例@inlinable func hoge() { print("hoge") }
@usableFromInline
@inlinable
の実装でアクセスする宣言に対して必要なattribute- アクセス制御修飾子をサポートするすべての宣言に適用可能
- internalで宣言されたものにのみ付与可能
例@inlinable func hoge() { print("hoge") fuga() } @usableFromInline func fuga() { print("fuga") }
@propertyWrapper
- プロパティの値にアクセスする方法を独自のattributeとして定義できる
- attributeを定義するにはこのattributeをclass,enum,structのいずれかに付与
- アクセス方法は
wrappedValue
プロパティのget、setを定義することで記述projectedValue
プロパティを定義することで、$プロパティ名でアクセス可能な値を定義できる- イニシャライザでattributeに初期値を与えることも可能
例@propertyWrapper struct SmallNumber { private var max: Int private var number: Int var projectedValue = false var wrappedValue: Int { get { return number } set { number = min(newValue, max) projectedValue = newValue > max } } init(wrappedValue: Int, max: Int) { self.number = min(wrappedValue, max) self.max = max } } struct SmallPoint { @SmallNumber(wrappedValue: 5, max: 10) var x: Int @SmallNumber(wrappedValue: 5, max: 10) var y: Int } var smallPoint = SmallPoint() print(smallPoint.x) // 5 print(smallPoint.$x) // false smallPoint.x = 200 print(smallPoint.$x) // true print(smallPoint.x) // 10
@requires_stored_property_inits
- クラス定義に付与することで、すべてのストアドプロパティのデフォルト値を要求する
- NSManagedObjectを継承するクラスでは暗黙的に付与される
例@requires_stored_property_inits class Hoge { // error: Stored property 'number' requires an initial value let number: Int init(number: Int) { self.number = number } }
@warn_unqualified_access
- トップレベルの関数、インスタンスメソッド、classメソッド、staticメソッドに付与することで、モジュール名や型名、インスタンス変数やインスタンス定数など、メソッドを特定するものがない場合にwarningを発生させる
- 同一スコープ内で同名の関数にアクセス可能な場合に曖昧さをなくすのに役立つ
- Sequenceのmin()で利用
例@warn_unqualified_access func min() -> Self.Element? { /// }
@unknown
- 将来的に新しいcaseが追加された場合に、そのケースをhandlingできるようにする
- コンパイル時にはenumが網羅されていない旨のwarningが発生する
例enum Signal { case red case yellow case green case purple // 新しいcase } let signal = Signal.yellow switch signal { // warning: Switch must be exhaustive case .red: print("red") case .yellow: print("yellow") case .green: print("green") @unknown default: print("未知のケース") }参考