ObjecTips

Swift & Objective-C で iOS とか macOS とか

iOS 11 Messages Framework の変更点

iOS 11 関連記事
iOS 11 UIKit の変更点 - ObjecTips
iOS 11 Foundation の変更点 - ObjecTips
iOS 11 PDFKit - ObjecTips
iOS 11 Core Image の変更点 - ObjecTips
Vision framework でテキスト検出 TextDetection - ObjecTips
Vision Framework で水平角検出(傾き) Horizon Detection - ObjecTips

Messages Framework

MSConversation
- (void)sendMessage:(MSMessage *)message completionHandler:(nullable void (^)(NSError *_Nullable error))completionHandler NS_AVAILABLE_IOS(11_0);
- (void)sendSticker:(MSSticker *)sticker completionHandler:(nullable void (^)(NSError *_Nullable error))completionHandler NS_AVAILABLE_IOS(11_0);
- (void)sendText:(NSString *)text completionHandler:(nullable void (^)(NSError *_Nullable error))completionHandler NS_AVAILABLE_IOS(11_0);
- (void)sendAttachment:(NSURL *)URL withAlternateFilename:(nullable NSString *)filename completionHandler:(nullable void (^)(NSError *_Nullable error))completionHandler NS_AVAILABLE_IOS(11_0);

これまではテキスト入力エリアにテキストや画像、ステッカーを入力、添付する事しか出来ず送信のアクションはユーザ自身が送信ボタンを押す必要があった。
送信の最終決定権はユーザにあるという事でポリシーとして納得していたけど iOS 11 では送信アクション自体をアプリから実行する事が出来るらしい。
アプリがバグってたらユーザの意図しない内容のメッセージが送られたりしてしまうけど本当にユーザのプレビューと送信アクション無しで大丈夫かな?
その心配より利便性を取ったのかも知れない。ユーザは便利になる一方開発者にはより責任が求められる。

MSMessagesAppPresentationStyle
MSMessagesAppPresentationStyleTranscript NS_ENUM_AVAILABLE_IOS(11_0),

MSMessagesAppViewController の表示状態を表すものとして Compact と Expand があったがそれに追加で Transcript という状態が加わったらしい。

MSMessagesAppCompactOrExpandedPresentation
MSMessagesAppTranscriptPresentation

この2つのプロトコルも追加された。

MSMessageLiveLayout
NS_CLASS_AVAILABLE_IOS(11_0)
@interface MSMessageLiveLayout : MSMessageLayout

ライブレイアウトが何かは分からないけど多分WWDCのセッションでデモが行われるだろう。
ライブレイアウト非対応のデバイスでは以下のレイアウトが使われるとの事。

@property (nonatomic, readonly) MSMessageTemplateLayout *alternateLayout;
MSMessageErrorCode
    MSMessageErrorCodeUnknown NS_ENUM_AVAILABLE_IOS(11_0) = -1,
    MSMessageErrorCodeSendWithoutRecentInteraction NS_ENUM_AVAILABLE_IOS(11_0),
    MSMessageErrorCodeSendWhileNotVisible NS_ENUM_AVAILABLE_IOS(11_0),

ドキュメントが無いので詳細が分からないけど

  • 1つめは不明なエラー
  • 2つ目はユーザが何も操作していない状態で送信を実行した時のエラー
  • 3つ目はアプリが表示されていない時に送信を実行した時のエラー。

おそらく後ろ2つについてはプログラムからメッセージの送信を実行出来る様になったとは言え、これらのケースの様なユーザが認識しないタイミングで勝手にメッセージを送信させないというポリシーに基づいてエラーが発生する様になっているんだと思う。

まとめ

アプリからメッセージ送信を実行出来る、でも変なタイミングで送ってもエラーが起きる。
ライブレイアウトはセッションの情報待ち。

Vision Framework でテキスト検出 Text Detection

iOS 11 関連記事
iOS 11 UIKit の変更点 - ObjecTips
iOS 11 Foundation の変更点 - ObjecTips
iOS 11 Messages Framework の変更点 - ObjecTips
iOS 11 PDFKit - ObjecTips
iOS 11 Core Image の変更点 - ObjecTips
koze.hatenablog.jp

Vision Framework

iOS 11で Computer Vision の Framework が追加された。

Vision | Apple Developer Documentation

使えるのは以下

  • Face Detection and Recognition - 顔とパーツの認識
  • Machine Learning Image Analysis - 機械学習による画像分析
  • Barcode Detection - バーコードの検出
  • Image Alignment Analysis - 画像の並び解析
  • Text Detection - テキストの検出
  • Horizon Detection - 水平角の検出(傾き)
  • Object Detection and Tracking - 物体検出と追跡

特に機械学習による画像分析は MLModel -> VNCoreMLModel -> VNCoreMLRequest の流れで任意のモデルから分析を行える様になっているので、機能を限定されず自由に機械学習による画像分析が出来る模様。
これめちゃくちゃパワフルだと思う。

それはまた後で勉強するとして、まずは手始めに以前 Core Image でもやったテキスト検出を Vision framework で試してみる。
現時点でプログラミングガイドが見あたらないけど大体のクラスとメソッド名で理解できる様なシンプルな構成になっている。

実装

Text Detection with Vision framework

まず VNImageRequestHandler を作成。
NSURL の他に CVPixelBufferRef CGImageRef CIImage NSData を引数にするイニシャライザがあってどんな画像ソースも扱える様になっている。
UIImage なら一旦 CIImage を一旦経由すればいい。

次に VNDetectTextRectanglesRequest を作成して CompletionHandler を設定。
init してから設定するなら以下のメソッドでハンドラを設定

@property (readonly, nonatomic, copy, nullable) VNRequestCompletionHandler completionHandler;

init と同時に設定するなら以下のメソッドが使える。

- (instancetype) initWithCompletionHandler:(nullable VNRequestCompletionHandler)completionHandler NS_DESIGNATED_INITIALIZER;

次に reportCharacterBoxesYES に設定。
設定しないと文字領域のかたまりのみを検出する。YES だと1文字ずつの矩形を検出する。

最後に performRequests: でリクエストを実行する 。

実行結果

このコードを以下の画像に対して実行する。

f:id:Koze:20170607111252p:plain

結果は以下

{{0.19375000000000001, 0.546875}, {0.49687500000000007, 0.140625}}
 |-{{0.19375000000000001, 0.546875}, {0.09375, 0.10625}}
 |-{{0.29999999999999999, 0.546875}, {0.087499999999999994, 0.140625}}
 |-{{0.39687499999999998, 0.546875}, {0.087499999999999994, 0.10625}}
 |-{{0.49062499999999998, 0.546875}, {0.090624999999999997, 0.140625}}
 |-{{0.59999999999999998, 0.546875}, {0.090624999999999997, 0.10625}}
{{0.19062499999999999, 0.32187500000000002}, {0.63125000000000009, 0.14374999999999993}}
 |-{{0.19062499999999999, 0.32500000000000001}, {0.11874999999999999, 0.13750000000000001}}
 |-{{0.32500000000000001, 0.32500000000000001}, {0.10625, 0.13750000000000001}}
 |-{{0.44374999999999998, 0.32187499999999997}, {0.121875, 0.14374999999999999}}
 |-{{0.58750000000000002, 0.32500000000000001}, {0.1125, 0.13750000000000001}}
 |-{{0.72187500000000004, 0.32500000000000001}, {0.10000000000000001, 0.13750000000000001}}

検出できてるっぽい。
ちなみに NSStringFromCGRect を使わなくても直接オブジェクトをログ出力する事も出来る。こっちの方が分かりやすいかも。
VNTextObservation の uuid と精度(以下では全て1)も一緒に出力される。

2017-06-07 11:30:09.026853+0900 Test[10183:7799799] <VNTextObservation: 0x600000299f50> D1AA25AD-7749-40F5-A893-C6FCB75AEE94 1 [0.19375 0.546875 0.496875 0.140625]
2017-06-07 11:30:09.027137+0900 Test[10183:7799799] (
    "<_VNTextObservationCharacterBox: 0x6000008f8880> 91A22E36-C52E-436F-B4B0-DAE1B0CFAD8E 1 [0.19375 0.546875 0.09375 0.10625]",
    "<_VNTextObservationCharacterBox: 0x6000008f8980> 20338509-1DA5-408F-BBC2-993AF9EB561B 1 [0.3 0.546875 0.0875 0.140625]",
    "<_VNTextObservationCharacterBox: 0x6000008f8a80> EDD81518-D291-4DEC-932B-72F8FCC3C489 1 [0.396875 0.546875 0.0875 0.10625]",
    "<_VNTextObservationCharacterBox: 0x6000008f8b80> 86DA1678-ABC8-4833-B8A7-D2697A85D89F 1 [0.490625 0.546875 0.090625 0.140625]",
    "<_VNTextObservationCharacterBox: 0x6000008fcf00> 85447B91-87EA-4275-B837-5160FE01C2B3 1 [0.6 0.546875 0.090625 0.10625]"
)
2017-06-07 11:30:09.027244+0900 Test[10183:7799799] <VNTextObservation: 0x60000029ad60> F2E588DD-9AFE-4E2E-ADE6-10230EB22919 1 [0.190625 0.321875 0.63125 0.14375]
2017-06-07 11:30:09.027360+0900 Test[10183:7799799] (
    "<_VNTextObservationCharacterBox: 0x6000008fd480> C336A62D-F607-47F4-B0EB-E98D03E3A9F7 1 [0.190625 0.325 0.11875 0.1375]",
    "<_VNTextObservationCharacterBox: 0x6000008fd580> 3917DF3A-13CF-4E63-B66F-4408EAEB5B0E 1 [0.325 0.325 0.10625 0.1375]",
    "<_VNTextObservationCharacterBox: 0x6000008fd680> 06B97257-B8A5-417A-A0F6-64778AADE759 1 [0.44375 0.321875 0.121875 0.14375]",
    "<_VNTextObservationCharacterBox: 0x6000008f2900> 85A90B06-0F4C-4203-8427-59877D7DCAA2 1 [0.5875 0.325 0.1125 0.1375]",
    "<_VNTextObservationCharacterBox: 0x6000008f2800> 91530E7D-2891-4847-9031-603519071065 1 [0.721875 0.325 0.1 0.1375]"
)
結果のオーバーレイ

検出結果は0-1の範囲の様なのでこれを元にオーバーレイ画像を作成してみる。

Overlay Image from VNTextObservation

Core Image の時と同様、上下逆の座標で結果が返ってくるので途中に CGAffineTransform を使って座標を変換している。
結果は以下

f:id:Koze:20170607115927p:plain

バッチリ

日本語に対しても実行してみる。

f:id:Koze:20170607121311p:plain

平仮名がパーツで分割して認識されていたり漢字が認識されていなかったりするけど、以前は平仮名の行自体が検出されていなかったので検出精度は上がっている。


Core Image バージョンは以下
やってる事はそんなに変わらない。検出結果の座標系が違うのでオーバーレイ画像の作成処理は変わってくる。

koze.hatenablog.jp

ちなみに Core Image バージョンでも iOS 11 であれば Vision と同じで平仮名の検出が出来る様になっていた。
おそらく中身の処理は同じで、結果の違いはOSのバージョンの差異によるものだと思う。 *1

Core Image と Vision では文字の矩形のみの検出だけど、その先の文字内容の認識(OCR)を行う部分は iOS 11 で追加された機械学習の Core ML framework や Vision framework の VNCoreMLRequest で独自のモデルを使って各自どうぞって事なんだと思う。

*1:追記:Session 506 - Vision Framework: Building on Core ML によれば、顔認識については Vision では機械学習を使っていて Core Image の顔認識と比べて精度、処理速度、バッテリー処理の面で Vision の方が優位との事

iOS 11 Foundation の変更点

Foundation | Apple Developer Documentation

Foundation 周りざっくり、網羅はしていない。

iOS 11 関連記事
iOS 11 UIKit の変更点 - ObjecTips
iOS 11 Messages Framework の変更点 - ObjecTips
iOS 11 PDFKit - ObjecTips
iOS 11 Core Image の変更点 - ObjecTips
Vision framework でテキスト検出 TextDetection - ObjecTips
Vision Framework で水平角検出(傾き) Horizon Detection - ObjecTips

NSLinguisticTagger

言語、品詞の判定周りのメソッドが色々と増えたっぽい。
Core MLのドキュメントによると NSLinguisticTagger クラスには Machine Learning が生かされているらしい。

NSFileManager
- (BOOL)trashItemAtURL:(NSURL *)url resultingItemURL:(NSURL * _Nullable * _Nullable)outResultingURL error:(NSError **)error API_AVAILABLE(macos(10.8), ios(11.0)) API_UNAVAILABLE(watchos, tvos);

macOS では昔からあったメソッド。iOS にもシステム共通のゴミ箱が登場?

    NSTrashDirectory API_AVAILABLE(macos(10.8), ios(11.0)) API_UNAVAILABLE(watchos, tvos) = 102             // location of Trash directory

証拠発見か?
NSSearchPathDirectoryNSTrashDirectory がiOSでも利用可能に

NSJSONSerialization
    NSJSONWritingSortedKeys API_AVAILABLE(macos(10.13), ios(11.0), watchos(4.0), tvos(11.0)) = (1UL << 1)

JSONの保存オプションでキーのソートが可能に

NSProcessInfo
typedef NS_ENUM(NSInteger, NSProcessInfoThermalState) {
    NSProcessInfoThermalStateNominal,
    NSProcessInfoThermalStateFair,
    NSProcessInfoThermalStateSerious,
    NSProcessInfoThermalStateCritical
} API_AVAILABLE(macosx(10.10.3), ios(11.0), watchos(4.0), tvos(11.0));

デバイスのパワー使い過ぎによる熱状態を取得出来る。

FOUNDATION_EXTERN NSNotificationName const NSProcessInfoThermalStateDidChangeNotification API_AVAILABLE(macosx(10.10.3), ios(11.0), watchos(4.0), tvos(11.0));

変更通知も受け取れる。

まとめ

他にも変更のあるクラスはいくつかあったけど、個人的におおっと思う大きな変化は無かったかも。
テキストからの言語判定はこれまでいまいち精度が出なかったので Machine Learning が生かされてる NSLinguisticTagger の言語判定は是非とも試してみたい。

iOS 11 UIKit の変更点

UIKit | Apple Developer Documentation

UIKit 周りざっくり、網羅はしていない。

iOS 11 関連記事
iOS 11 Foundation の変更点 - ObjecTips
iOS 11 Messages Framework の変更点 - ObjecTips
iOS 11 PDFKit - ObjecTips
iOS 11 Core Image の変更点 - ObjecTips
Vision Framework でテキスト検出 Text Detection - ObjecTips
Vision Framework で水平角検出(傾き) Horizon Detection - ObjecTips

変更点

ContentSizeCategory の比較とアクセシビリティチェックの関数が追加
UIKIT_EXTERN BOOL UIContentSizeCategoryIsAccessibilityCategory(UIContentSizeCategory category) API_AVAILABLE(ios(11.0),tvos(11.0),watchos(4.0)) NS_REFINED_FOR_SWIFT;
UIKIT_EXTERN NSComparisonResult UIContentSizeCategoryCompareToCategory(UIContentSizeCategory lhs, UIContentSizeCategory rhs) API_AVAILABLE(ios(11.0),tvos(11.0),watchos(4.0)) NS_REFINED_FOR_SWIFT;
ドラッグ&ドロップ周りの追加クラスやプロトコル

UIPasteConfiguration
UIPasteConfigurationSupporting
UIInteraction
UICollectionViewDragDelegate UICollectionViewDropDelegate
UICollectionViewReorderingCadence
UITableViewDragDelegate UITableViewDropDelegate

NSFileProviderExtension

NSFileProviderExtension - FileProvider | Apple Developer Documentation

Extension からフォルダを作ったりファイルをリネームしたり tag とか favoriteRank を編集したり出来るようになるらしい。

UITextDocumentProxy
@property (nullable, nonatomic, readonly) NSString *selectedText API_AVAILABLE(ios(11.0));

ユーザが選択中のテキストを取得できるようになった。
キーボードExtensionで入力中のテキストから再変換をかけたり絵文字に変換したりといった機能を実装出来そう。

@property (nonatomic, readonly, copy) NSUUID *documentIdentifier API_AVAILABLE(ios(11.0));

用途が思いつかない。
新しくテキスト入力しているのか、前回中断したテキスト入力作業の続きかを判断するのに使える?

UIInputViewController
@property (nonatomic, readonly) BOOL hasFullAccess API_AVAILABLE(ios(11.0));

キーボードアプリからフルアクセスが許可されているかどうかの状態チェックが可能に。
確か以前はユーザデータにアクセスしてみてアクセス出来なかったらフルアクセスが許可されていない、みたいな方法でチェックする必要があったはず。

@property (nonatomic, readonly) BOOL needsInputModeSwitchKey API_AVAILABLE(ios(11.0));

おそらくiOS 11では地球儀ボタンの表示が必要な時とそうでないケースがあるっぽい。
(追記:リリース後にiPhone XのためのAPIだと判明。iPhone Xでは地球儀マークはキーボードの左下に標準で用意される。)

UIView
@property(nonatomic) BOOL accessibilityIgnoresInvertColors API_AVAILABLE(ios(11_0), tvos(11_0));

これを YES にすると、アクセシビリティの白黒反転をViewとそのSubviewsでは反映しないように出来るらしい。
画像やビデオなど表示される色が変わると困るものに対して使うような用途を想定しているらしい。

UICollectionView
- (BOOL)collectionView:(UICollectionView *)collectionView shouldSpringLoadItemAtIndexPath:(NSIndexPath *)indexPath withContext:(id<UISpringLoadedInteractionContext>)context API_AVAILABLE(ios(11.0)) API_UNAVAILABLE(tvos, watchos);

NO を返すと Spring Loading? のオプトアウトが出来るらしい。

その他 UICollectionViewDragDelegate UICollectionViewDropDelegate
UICollectionViewReorderingCadence
などドラッグ&ドロップ周りのAPIがいくつか追加

UITableView
- (nullable UISwipeActionsConfiguration *)tableView:(UITableView *)tableView leadingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath API_AVAILABLE(ios(11.0)) API_UNAVAILABLE(tvos);
- (nullable UISwipeActionsConfiguration *)tableView:(UITableView *)tableView trailingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath API_AVAILABLE(ios(11.0)) API_UNAVAILABLE(tvos);

テーブルセルの横スワイプ時のボタン表示機能を提供する UITableViewRowAction の進化版の UIContextualAction が追加。
これを UISwipeActionsConfiguration と組み合わせて使うらしい。
UITableViewRowAction ではタイトルと背景色しか設定出来なかったのが画像も設定出来るようになっている。
さらに UISwipeActionsConfiguration の設定で、メールアプリで使われているようなフルスワイプした時のアクションの実行を実装出来る。(セルのスワイプで表示されるボタンを押さなくても、スワイプ操作だけでアクションを起こす事が出来るという事)

- (BOOL)tableView:(UITableView *)tableView shouldSpringLoadRowAtIndexPath:(NSIndexPath *)indexPath withContext:(id<UISpringLoadedInteractionContext>)context API_AVAILABLE(ios(11.0)) API_UNAVAILABLE(tvos, watchos);

NO を返すと Spring Loading? のオプトアウトが出来るらしい。

- (void)performBatchUpdates:(void (NS_NOESCAPE ^ _Nullable)(void))updates completion:(void (^ _Nullable)(BOOL finished))completion API_AVAILABLE(ios(11.0), tvos(11.0));

UICollectionView で既にあるバッチ更新が追加

その他 UITableViewDragDelegate UITableViewDropDelegate
などドラッグ&ドロップ周りのAPIがいくつか追加

UIScrollView

UIViewControllerautomaticallyAdjustsScrollViewInsets

@property(nonatomic, assign) BOOL automaticallyAdjustsScrollViewInsets;

が deprecated になって、代わりに UIScrollView に adjust inset 関連のAPIが色々と追加された。
今後はこっちでうまく制御しろという事か。

@property(nonatomic, readonly) UIGestureRecognizer *directionalPressGestureRecognizer API_DEPRECATED("Configuring the panGestureRecognizer for indirect scrolling automatically supports directional presses now, so this property is no longer useful.", tvos(9.0, 11.0));

ドキュメントでは追加メソッドだけどヘッダを見たら deprecated になっているのでリリースまでに消えて無くなるかも、、

UIImageView
@property (nonatomic, strong, readonly) UIView *overlayContentView UIKIT_AVAILABLE_TVOS_ONLY(11_0);

tvOS 用のメソッド。UIImageView の上に重ねてViewを表示する、、ってのがこれまで tvOS では出来なかったのかな。

UIButton
UIButtonTypePlain

tvOS 用のメソッド 。ブラー背景の無いシステム標準ボタンらしい。

UIBarButtonItem

UIBarButtonSystemItemPageCurl が deprecated

UINavigationBar
@property (nonatomic, readwrite, assign) BOOL prefersLargeTitles UI_APPEARANCE_SELECTOR API_AVAILABLE(ios(11.0)); //API_UNAVAILABLE(tvos)

iOS 11の電話アプリの様にタイトル表示を大きくする設定。

UIViewController
@property(nonatomic,readonly,strong) id<UILayoutSupport> topLayoutGuide API_DEPRECATED_WITH_REPLACEMENT("-[UIView safeAreaLayoutGuide]", ios(7.0,11.0), tvos(7.0,11.0));
@property(nonatomic,readonly,strong) id<UILayoutSupport> bottomLayoutGuide API_DEPRECATED_WITH_REPLACEMENT("-[UIView safeAreaLayoutGuide]", ios(7.0,11.0), tvos(7.0,11.0));

layoutGuide が deprecated、safeAreaLayoutGuide ってのを使うらしい。
layoutGuide は結構使ってるので分岐が面倒そう。

@property(nonatomic,assign) BOOL automaticallyAdjustsScrollViewInsets API_DEPRECATED_WITH_REPLACEMENT("Use UIScrollView's contentInsetAdjustmentBehavior instead", ios(7.0,11.0),tvos(7.0,11.0)); // Defaults to YES

deprecated、UIScrollViewcontentInsetAdjustmentBehavior を使えとの事。

UISplitViewController
@property(nonatomic) UISplitViewControllerPrimaryEdge primaryEdge API_AVAILABLE(ios(11.0), tvos(11.0)); // default: UISplitViewControllerPrimaryEdgeLeading

先頭と後ろとどっちが primary かを設定出来るらしい。設定するとどう変わるのかは不明。

UINavigationItem
@property (nonatomic, readwrite, assign) UINavigationItemLargeTitleDisplayMode largeTitleDisplayMode API_AVAILABLE(ios(11.0)); //API_UNAVAILABLE(tvos)

ラージタイトルの表示モード

UINavigationBar
@property (nonatomic, readwrite, assign) BOOL prefersLargeTitles UI_APPEARANCE_SELECTOR API_AVAILABLE(ios(11.0)); //API_UNAVAILABLE(tvos)

ラージタイトルの表示設定

NSLayoutXAxisAnchor, NSLayoutYAxisAnchor
- (NSLayoutConstraint *)constraintEqualToSystemSpacingAfterAnchor:(NSLayoutXAxisAnchor *)anchor multiplier:(CGFloat)multiplier API_AVAILABLE(ios(11.0),tvos(11.0));
- (NSLayoutConstraint *)constraintGreaterThanOrEqualToSystemSpacingAfterAnchor:(NSLayoutXAxisAnchor *)anchor multiplier:(CGFloat)multiplier API_AVAILABLE(ios(11.0),tvos(11.0));
- (NSLayoutConstraint *)constraintLessThanOrEqualToSystemSpacingAfterAnchor:(NSLayoutXAxisAnchor *)anchor multiplier:(CGFloat)multiplier API_AVAILABLE(ios(11.0),tvos(11.0));

- (NSLayoutConstraint *)constraintEqualToSystemSpacingBelowAnchor:(NSLayoutYAxisAnchor *)anchor multiplier:(CGFloat)multiplier API_AVAILABLE(ios(11.0),tvos(11.0));
- (NSLayoutConstraint *)constraintGreaterThanOrEqualToSystemSpacingBelowAnchor:(NSLayoutYAxisAnchor *)anchor multiplier:(CGFloat)multiplier API_AVAILABLE(ios(11.0),tvos(11.0));
- (NSLayoutConstraint *)constraintLessThanOrEqualToSystemSpacingBelowAnchor:(NSLayoutYAxisAnchor *)anchor multiplier:(CGFloat)multiplier API_AVAILABLE(ios(11.0),tvos(11.0));

iOS 11では system space っていう概念が追加されるらしい。

UIImagePickerController
@property(nonatomic)           UIImagePickerControllerQualityType    videoQuality NS_DEPRECATED_IOS(3_1, 11_0, "Use videoExportPreset");         // default value is UIImagePickerControllerQualityTypeMedium. If the cameraDevice does not support the videoQuality, it will use the default value.

取得するビデオの画質設定が deprecated、videoExportPreset を使えとの事。

@property(nonatomic, copy)     NSString                              *videoExportPreset NS_AVAILABLE_IOS(11_0);   // default value is AVAssetExportPresetMediumQuality. NSString (of one of the AVAssetExportPreset* constants). // Specifying a value for videoExportPreset will override a value specified for videoQuality

取得するビデオの画質設定方法が AVFoundation ベースに変更。プリセットは豊富なので以前より柔軟になった。

@property(nonatomic) UIImagePickerControllerImageURLExportPreset imageExportPreset NS_AVAILABLE_IOS(11_0);   // default value is UIImagePickerControllerImageExportPresetCompatible.

取得する画像の画質設定っぽいけど、ドキュメントにもヘッダにも詳細の記載が無いので不明

UIKIT_EXTERN NSString *const UIImagePickerControllerReferenceURL        NS_DEPRECATED_IOS(4_1, 11_0, "Replace with public API: UIImagePickerControllerPHAsset") __TVOS_PROHIBITED;  // an NSURL that references an asset in the AssetsLibrary framework
UIKIT_EXTERN NSString *const UIImagePickerControllerPHAsset NS_AVAILABLE_IOS(11_0) __TVOS_PROHIBITED;  // a PHAsset
UIKIT_EXTERN NSString *const UIImagePickerControllerImageURL NS_AVAILABLE_IOS(11_0) __TVOS_PROHIBITED;  // an NSURL

URL取得のキーが deprecated になって、PHAsset と画像のURLを指定して取得出来る様になった。

UIDocumentBrowserViewController

ローカルとiCloudのファイルにアクセス出来るらしい。
表示する contentType の指定やドキュメント作成の可否、複数項目の選択可否など macOS の NSOpenPanel ライクに使えそう。

UIDocumentPickerViewController
@property (nonatomic, assign) BOOL allowsMultipleSelection NS_AVAILABLE_IOS(11_0);
- (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentsAtURLs:(NSArray <NSURL *>*)urls NS_AVAILABLE_IOS(11_0);

複数項目の選択取得に対応

UIActivityType
UIActivityTypeMarkupAsPDF

アクティビティタイプの追加

Drag & Drop

追加が多いので以下URLで

Drag and Drop | Apple Developer Documentation

Drag and Drop Customization | Apple Developer Documentation

Accessibility
UIKIT_EXTERN NSString *const UIAccessibilityVoiceOverStatusChanged API_DEPRECATED_WITH_REPLACEMENT("UIAccessibilityVoiceOverStatusDidChangeNotification", ios(4.0, 11.0), tvos(9.0, 11.0));
UIKIT_EXTERN NSNotificationName const UIAccessibilityVoiceOverStatusDidChangeNotification API_AVAILABLE(ios(11.0), tvos(11.0));

ボイスオーバーのオンオフの変更通知の名称が変更。StatusChangedStatusDidChangeNotification のワードに変更しただけ。

UIGestureRecognizer
@property (nullable, nonatomic, copy) NSString *name API_AVAILABLE(ios(11.0), tvos(11.0)); // name for debugging to appear in logging

identifier として name を設定出来る様になった。ただヘッダのコメントではデバッグのためって書いてあるので、name で処理分岐を行ったりするのは適切では無さそう。

UIGraphicsImageRendererFormat
+ (instancetype)formatForTraitCollection:(UITraitCollection *)traitCollection NS_AVAILABLE_IOS(11_0);

UITraitCollection を引数に format を作成してくれるメソッドらしいだけど、scale とか UIGraphicsImageRendererFormat のパラメータを自分で設定するなら使う機会が無いかも。

UIColor
+ (nullable UIColor *)colorNamed:(NSString *)name NS_AVAILABLE_IOS(11_0);      // load from main bundle
+ (nullable UIColor *)colorNamed:(NSString *)name inBundle:(nullable NSBundle *)bundle compatibleWithTraitCollection:(nullable UITraitCollection *)traitCollection NS_AVAILABLE_IOS(11_0);

Named Color Assets 関連のメソッド。
Xcode 9では xcassets で画像と同じ様に色をアセットとして作成する事ができて、これらのメソッドで呼び出して使ったり Storyboard 上からも呼び出す事ができる。
カラーアセットを使えば全ボタンの色を変更したりアプリ全体の色管理が容易になるはず。

UIFontMetrics

ドキュメント無し

UITextInputTraits
UIKIT_EXTERN UITextContentType const UITextContentTypeUsername                  NS_AVAILABLE_IOS(11_0);
UIKIT_EXTERN UITextContentType const UITextContentTypePassword                  NS_AVAILABLE_IOS(11_0);

キーボードの入力タイプにユーザ名とパスワード用の入力タイプが追加

UITextSmartQuotesType
UITextSmartDashesType
UITextSmartInsertDeleteType

macOS のスマート引用符とスマートダッシュに相当する入力テキストの自動置き換え機能だと推測。
最後のは英語キーの時のスペースの自動入力と削除?


以下UIKitじゃ無いけどUI周りなのでまとめて

EventKitUI
EVENTKITUI_EXTERN NSBundle *EventKitUIBundle(void);

これ Private で使ってるAPIじゃないの?開発者には利用のしようが無い気がする。

MessageUI MFMailComposeViewController
- (void)setPreferredSendingEmailAddress:(NSString *)emailAddress API_AVAILABLE(ios(11.0));

メール送信UIで送信元(自分)のアドレスを指定出来る様になったらしい。
アプリの使用者のメールアドレスを把握している必要があるので、アカウント制のアプリでアカウントに紐付いたメールアドレスが分かっている場合や、利用ユーザを管理・把握している社内向けの業務アプリとかで活用出来そう。


まとめ

Named Color Assets の機能が最高。これは本当に色管理が楽になるはず。
あと UIDocumentBrowserViewController はユーザにとって便利で、これに対応しているどうかでアプリを選ぶ人も出てきそうな気がするので積極的に使っていきたい。
開発的にもこのクラスを使っておけばドキュメントの受け渡しの面倒な処理をしなくて良さそうなのでいい事尽くめだと思う。

App Storeでレビューする機能を実装する

iOS 10.3から登場する SKStoreReviewController のドキュメントにApp Storeのレビュー画面を直接開く方法がしれっと記載されている。

https://developer.apple.com/reference/storekit/skstorereviewcontroller/2851536-requestreview

アプリのURLのクエリに action=write-review を追加すればいいとの事。
例えば Apple の TestFight アプリを例にすると以下のコードになる

- (IBAction)review:(id)sender
{
    // 899247664 is identifier for TestFlight
    NSURL *URL = [NSURL URLWithString:@"https://itunes.apple.com/app/id899247664?action=write-review"];
    [[UIApplication sharedApplication] openURL:URL options:@{} completionHandler:nil];
}

この時の遷移の流れは以下のようになる

メソッド実行

f:id:Koze:20170202101009p:plain

アプリを離れて App Store へ遷移

f:id:Koze:20170202101258p:plain

レビュータブが選択された状態のアプリ紹介画面が一瞬表示される

f:id:Koze:20170202101404p:plain

即座にモーダルでレビュー記入画面が表示される(ログインが必要であればログイン)

f:id:Koze:20170202101636p:plain f:id:Koze:20170202101703p:plain

キャンセルorレビューを完了するとアプリ紹介画面へ戻る

f:id:Koze:20170202101404p:plain

このように action=write-review を使うと直接レビュー画面を開く事が出来る。
クエリ無しでURLを開いた場合はアプリ紹介画面の詳細タブが選択された状態で表示されるためユーザにレビュータブを選択してもらう操作が必要になる。
その点はスマートではないけどレビュータブを選択してレビューを書く前に「App サポート」の選択肢がユーザに提示されるので、もしアプリの使い方や不具合についてネガティブなレビュー書く前にサポートに連絡して欲しいという場合はクエリを使って直接レビュー記入画面を開かずに従来の方法でApp Storeに遷移するのも手かも知れない。
もしくはアプリ内でレビューボタンと不具合報告ボタンをきちんと分けておいて、不具合報告はサポートに直接連絡してもらうようなフローを取るのがいいと思う。


ちなみに iOS 10.3 の SKStoreReviewController を使ったレビュー機能はアプリ内にアラート形式のレーティング画面が出るだけなので非常に使いやすそうだけど、ドキュメントにあるようにメソッドを実行した時に常にアラートが出るわけではなくframework側でよしなに実行タイミングを決めてくれるものなので、ボタン操作などユーザのアクションに対してこのコントローラを使うのは不適切らしい。

UIImageView の画像をフェードインアウトさせて変更する

UIImageView に画像を設定する際にフワッとフェード(ディゾルブ)するようにするには、CALayerCATransition のアニメーションを加えてやる

コードは以下

    UIImageView *imageView = self.imageView;
    imageView.image = image; // 画像を変更
    [imageView.layer addAnimation:[CATransition animation] forKey:nil]; // アニメーションを追加

これでOK

CATiledLayer のフェードインエフェクトを解除する

CATiledLayer は表示時にデフォルトでフェードインエフェクトがかかるが CATiledLayer のサブクラスを作って以下のクラスメソッドをオーバーライドして 0 秒を返してやる事でフェードインしないようにする事が出来る。

+ (CFTimeInterval)fadeDuration;

実装は以下

あとは通常通り自前の描画処理を書くだけ。