Xcode6 Beta4 でアクセス修飾子がきた!

  • 158
    いいね
  • 9
    コメント
この記事は最終更新日から1年以上が経過しています。

Beta4がリリースされたので、変更点をいくつかピックアップしました。

待望のアクセスコントロールができるようになった

public, internal, privateのスコープでアクセスコントロールできるようになりました。

アクセス修飾子 説明
public 定義されているターゲット外からもアクセスすることができる
internal 定義されているターゲット内からアクセスすることができる
private 定義されているソースファイル内からアクセスすることができる

記載を処略した場合はinternalがデフォルトで適用されます。

// An example class in a framework target.
public class ListItem: NSObject {
    public var text: String
    public var isComplete: Bool
    // Readable throughout the module, but only writeable from
    // within this file.
    private(set) var UUID: NSUUID
    public init(text: String, completed: Bool, UUID: NSUUID) {
        self.text = text
        self.isComplete = completed
        self.UUID = UUID
    }
    func refreshIdentity() {
        self.UUID = NSUUID()
    }
    // Must be public because it overrides a public method and is
    itself
    // part of a public type.
    public override func isEqual(object: AnyObject?) -> Bool {
        if let item = object as? ListItem {
            return self.UUID == item.UUID 
        } 
        return false 
    } 
}

参考 Xcode Release Notes

Swift Enables Access Control
Swift access control has three access levels:
• private entities can only be accessed from within the source file where they are defined.
• internal entities can be accessed anywhere within the target where they are defined.
• public entities can be accessed from anywhere within the target and from any other context
that imports the current target’s module.

@IBOutletのプロパティ定義はオプショナルが必須になった

@IBOutletのプロパティが軒並みエラーになります。

WTDCommentCell_swift.jpg

お二人方からコメントでご指摘を頂いたので追記致します。ありがとうございます。m(_ _)m @7/22 16:00

[ 追記 ここから ]

以下のようなコンパイルエラーが表示されます。

WTDCommentCell_swift.jpg

エラーメッセージ

IBOutlet' property has non-optional type 'UILabel'

解決方法は2通りあります。

1.オプショナルを明記する Optionals(?)
2.暗黙的アンラップオプショナルを明記する Implicitly Unwrapped Optionals(!)

ストーリボードからドラッグ&ドロップで@IBOutletを作成すると以下のようになるので、2.の方が推奨されているようです。
また、ビューはaddSubviewされている場合、参照は親のビューが保持(strong)しているので、ここでの参照はweakが適切です。

WTDCommentCell_swift.jpg

暗黙的アンラップオプショナルは以下ような場面の利用が想定されます。

タイミング的にnilの時があるけど参照時には値がセットされていることが自明なとき

self.nameLabel.removeFromSuperview()

で、参照を破棄すると

self.nameLabel.text = "Hoge Fuga"

EXEC_BAD_INSTRUCTIONになるので気をつける必要があります。

[ 追記 ここまで ]

さらにコメントを頂いたので追記致します。ありがとうございます。m(_ _)m @7/23 10:30

[ 追記 その2 ここから ]

AppleのSwiftドキュメントでは以下の記載があります。

暗黙的アンラップオプショナルにすべき(推奨)

Using Swift with Cocoa and Objective-C

When you declare an outlet in Swift, you should make the type of the outlet an implicitly unwrapped optional.

Using_Swift_with_Cocoa_and_Objective-C__Writing_Swift_Classes_with_Objective-C_Behavior.jpg

とはいえ、このOutletのプロパティはnilになる可能性(※)があるので、プロパティにアクセスする場合はオプショナルを明示して利用しようかと考えています。

WTDCommentCell_swift.jpg

※ nilになる可能性

  • Storyboardからコネクションが正しく張れていない
  • 参照を保持している親ビューが開放された
  • プロパティのビュー自身がremoveFromSuperviewした
  • プロパティに明示的にnilを代入した
  • など

Outletのオプショナルをより堅牢に記述するには、についてコメント欄にて議論されています。
是非合わせてご参照ください。

補足

Beta3からBeta4でドキュメントも変更されています。
Beta3までは、Outletのプロパティはコンパイラが自動的に暗黙的アンラップオプショナルに変更していたようです。

When you declare an outlet in Swift, the compiler automatically converts the type to a weak implicitly unwrapped optional and assigns it an initial value of nil.

参照

Swiftでの@IBOutletの振る舞い

[ 追記 その2 ここまで ]

以下記述は取り消しました。

[ 取り消し ここから ]

オプショナルな設定にしてあげます

WTDCommentCell_swift.jpg

@IBOutletなプロパティを利用しているところは、値(参照)がセットされていると思うのでアンラップにしました。
オプショナルバインディングで記述するほうがより丁寧なのかもしれません

WTDCommentCell_swift.jpg

[ 取り消し ここまで ]

参考 Xcode Release Notes

Known issues in Xcode 6 beta 4
Swift
• You cannot conditionally assign to a property of an optional object. (16922562)

配列の要素の型指定の記法はBeta3以上の記法が必須になった

以下はBeta2までの記法で、Beta3から記法が変わりましたがエラーにはならずワーニングでしたが、Beta4からは必須になりました。

Edges_swift.jpg

Edges_swift.jpg

UIntができてIntとUIntを明示的な使い分けが必要になった

NSUInteger型に対応するUInt型はBeta3までなかったので、ObjCと連携するときはNSUInteger型はInt型を利用していました。Beta4からUInt型ができたので、NSUInteger型のところはUInt型に書き直す必要があります。

例えば以下のようなデリゲートでNSUInteger型を指定している場合

@protocol ViewPagerDataSource <NSObject>
- (NSUInteger)numberOfTabsForViewPager:(ViewPagerController *)viewPager;
- (UIView *)viewPager:(ViewPagerController *)viewPager viewForTabAtIndex:(NSUInteger)index;
end

SwiftではUInt型で記述します。

func numberOfTabsForViewPager(viewPager: ViewPagerController) -> UInt {
  ...
}

func viewPager(viewPager: ViewPagerController, viewForTabAtIndex index: UInt) -> UIView {
  ...
}
// => OK

ちなみにNSUInteger型はSwiftでは使えません。

func numberOfTabsForViewPager(viewPager: ViewPagerController) -> NSUInteger {
  ...
}

func viewPager(viewPager: ViewPagerController, viewForTabAtIndex index: NSUInteger) -> UIView {
  ...
}
// => ERROR Use of undeclared type 'NSUInteger'; did you mean to use 'Int'?

ランドマークアノテーションをサポート

以下の記法が利用できるようになりました。Xcodeのジャンプバーから対象に

//MARK:
//TODO:
//FIXME

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    //MARK: UITableViewDelegate

    override func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!) {
        ...
    }

全画面_2014_07_22_12_02.jpg

参考 Xcode Release Notes

Landmarks
Xcode now supports //MARK:, //TODO: and //FIXME landmarks to annotate your code and
lists them in the jump bar. (14768427)

StoryboardでUIScrollView系(UITableViewなど)を利用すると出るワーニングが消えた

StoryboardでAutoLayoutを使用時にUIScrollView系を利用すると、コンストレイントのワーニングが常に出ており取り除くこともできなかったのですが、このワーニングがでなくなりました。

Beta3まで以下のようなワーニングが出ていました。

Main_storyboard_—_Edited.jpg

Main_storyboard_—_Edited.jpg

感想

UIntのIntの使い分けはコンバージョンの記述が増え、IBOutletのオプショナルもアンラップの記述が増えるのでちょっと残念です。

アクセスコントロールはみんなが待望していたのでありがたいですね。ライブラリ配布の懸念もひとつ解消されました。