ObjecTips

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

iOS 13 で UIView の beginAnimations 等のアニメーション関連のメソッドが deprecated

タイトルの通り、iOS 13 で以下のメソッドが depecated になった。

UIView - UIKit | Apple Developer Documentation

Animating Views

class func beginAnimations(String?, context: UnsafeMutableRawPointer?)
class func commitAnimations()
class func setAnimationStart(Date)
class func setAnimationsEnabled(Bool)
class func setAnimationDelegate(Any?)
class func setAnimationWillStart(Selector?)
class func setAnimationDidStop(Selector?)
class func setAnimationDuration(TimeInterval)
class func setAnimationDelay(TimeInterval)
class func setAnimationCurve(UIView.AnimationCurve)
class func setAnimationRepeatCount(Float)
class func setAnimationRepeatAutoreverses(Bool)
class func setAnimationBeginsFromCurrentState(Bool)
class func setAnimationTransition(UIView.AnimationTransition, for: UIView, cache: Bool)

代替が無くて困るという訳ではないけど既存コードの置き換えが必要になってくる。

beginAnimations, commitAnimations の置き換え

従来は begincommit の間に処理を書けば良いだけだったのが、新パターン*1では Xcode での警告 Use the block-based animation API instead の通りブロックベースのAPIを使う必要があり、また animatedtruefalse の時で呼び出すメソッドも変わってくるため一度処理をブロックでまとめてそれぞれのメソッドの引数に渡す必要がある。

    func setShowsSomething(_ shows: Bool, animated: Bool) {
        let block = {
            // do something
        }
        if animated {
            UIView.animate(withDuration: CATransaction.animationDuration(),
                           animations: block)
        }
        else {
            UIView.performWithoutAnimation(block)
        }
    }

また、別のアニメーション処理からこのメソッドが呼び出された際にも正しく指定した時間でアニメーション処理を行って欲しい場合は overrideInheritedDuration: UIView.AnimationOptions オプションを使うと良い。

    func setShowsSomething(_ shows: Bool, animated: Bool) {
        let block = {
            // do something
        }
        if animated {
            UIView.animate(withDuration: CATransaction.animationDuration(),
                           delay: 0,
                           options: [.overrideInheritedDuration],
                           animations: block)
        }
        else {
            UIView.performWithoutAnimation(block)
        }
    }

逆にこのオプションを指定しない場合は別アニメーションで指定されたアニメーション時間が継承されてアニメーションが発生する事になる。

    UIView.animate(withDuration: 1.0) {
        self.view1.backgroundColor = .red
        UIView.animate(withDuration: 0.2) { // 0.2 は無視されて1.0で動作する
            self.view2.backgroundColor = .red
        }
    }

継承と上書きのどちらが良いかはケースバイケースだろうけど継承されるのがデフォルトの挙動というのは一応気にした方がいいと思う。

Duration に 0 を指定すればどうか?

animatedfalse の時はアニメーション時間を0にすれば挙動は同じでは?と思うかも知れない(この実装例はまま見る)。
この場合条件分岐は三項演算子で animated ? CATransaction.animationDuration() : 0 とシンプルに書けるしブロックの変数化も不要で直接記述出来る。

    func setShowsSomething(_ shows: Bool, animated: Bool) {
        UIView.animate(withDuration: animated ? CATransaction.animationDuration() : 0,
                       animations: {
                        // do something
        })
    }

1つ気を付けなければならないのはアニメーション時間の継承の問題で、例えば上記のメソッドを以下の様に呼んだとすると*2 animated: false にも関わらず実際には1.0秒のアニメーションが発生してしまう。

UIView.animate(withDuration: 1.0) {
    setShowsSomething(true, animated: false) // 1.0秒でアニメーション動作
}

上記の挙動を避けるには animated false の際には performWithoutAnimation を使うか、 withDuration: 0 を指定する場合は以下の様にやはり overrideInheritedDuration: UIView.AnimationOptions オプションを使って実装する必要がある。

        UIView.animate(withDuration: animated ? CATransaction.animationDuration() : 0,
                       delay: 0,
                       options: [.overrideInheritedDuration],
                       animations: {
                        // do something
        })

余談 performWithoutAnimation と animate:withDuration: 0 の挙動の違い

performWithoutAnimation animate:withDuration: 0 は挙動が違う点があって、ブロック処理内でさらに呼び出された他の処理のアニメーションが有効か否かが変わってくる。 performWithoutAnimation が間に挟まるとそれ以下のネストではアニメーションが発生しなくなる。

アニメーションしない

UIView.animate(withDuration: 1.0) {
    UIView.performWithoutAnimation {
        UIView.animate(withDuration: 0.2) {
            // without animation
        }
    }
}

1.0秒でアニメーション

UIView.animate(withDuration: 1.0) {
    UIView.animate(withDuration: 0) {
        UIView.animate(withDuration: 0.2) {
            // animate with 1.0 sec
        }
    }
}

performWithoutAnimation を挟むと overrideInheritedDuration があろうともアニメーションしない

UIView.animate(withDuration: 1.0) {
    UIView.performWithoutAnimation {
        UIView.animate(withDuration: 0.2,
                       delay: 0,
                       options: [.overrideInheritedDuration],
                       animations: {
                        // without animation
        })
    }
}

0.2秒でアニメーション

UIView.animate(withDuration: 1.0) {
    UIView.animate(withDuration: 0) {
        UIView.animate(withDuration: 0.2,
                       delay: 0,
                       options: [.overrideInheritedDuration],
                       animations: {
                        // animate with 0.2 sec
        })
    }
}

余談 performWithoutAnimation と animate:withDuration: 0 のパフォーマンスの違い

以下のコードでそれぞれを10,000回呼び出してみたところおおよそ以下の様な結果に。
やはりアニメーション無し指定の方がパフォーマンスが良いが現実的なケースでは無いのであくまで参考程度に。

iOS 13, iPhone XS iOS 13, iPad Pro 11インチ
performWithoutAnimation 0.06-0.07sec 0.064-0.074sec
animate:withDuration: 0 2.74sec 2.74sec
    @IBAction func test1() {
        let start = CFAbsoluteTimeGetCurrent()
        let view = self.view
        for _ in 0..<10000 {
            UIView.performWithoutAnimation {
                view?.alpha = CGFloat.random(in: 0..<1)
            }
        }
        let end = CFAbsoluteTimeGetCurrent()
        print(#function, end - start)
    }

    @IBAction func test2() {
        let start = CFAbsoluteTimeGetCurrent()
        let view = self.view
        for _ in 0..<10000 {
            UIView.animate(withDuration: 0) {
                view?.alpha = CGFloat.random(in: 0..<1)
            }
        }
        let end = CFAbsoluteTimeGetCurrent()
        print(#function, end - start)
    }

結論

アニメーション無しの際にネスト以下もアニメーションを無しにするのであれば animated false では performWithoutAnimation を使う。
ネストとパフォーマンスをケアする必要が無い場合は三項演算子+ブロックの直接記述が楽。
overrideInheritedDuration オプションはケースバイケースで。

最後に duration について

アニメーションのデフォルト値の取得には CATransaction.animationDuration() を使ったがこのメソッドの実際の返り値は 0.25 になる。
しかし UIView.beginAnimations() で処理を行った際に UIView.inheritedAnimationDuration でデフォルトのアニメーション時間を確認してみるとこちらでは 0.2 が取得されるので*3、厳密に挙動を揃えたいのであれば CATransaction.animationDuration() は使わずに 0.2 を指定する必要がある。

print(CATransaction.animationDuration()) // 0.25

UIView.beginAnimations(nil, context: nil)
print(UIView.inheritedAnimationDuration)  // 0.2
UIView.commitAnimations()

*1:とは言えiOS 4.0以降のメソッドなので全く新しくは無い

*2:こんな意味不明なコード自体書くなという話は置いといて、メソッドの利用者が自分の書いたコードをどう使うかまでは制御出来ないのでメソッド側でどこまでケアすべきかという観点で、、と長々と釈明

*3:何年か前にデフォルトアニメーションの時間を調べた時に0.25だった気がするけどデフォルト値が変わったのか記憶違いなのか

iOS 13 beta 3 で追加された Core Image API

前回までの変更点

koze.hatenablog.jp

今回は iOS 13 beta 3 で変更点をチェック。
追加フィルタは1つで、他若干の追加APIが見られた。

https://gist.github.com/Koze/86315376f00fa44662f0d841f046e5d2/revisions

iOS 13 beta 3

CIRoundedRectangleGenerator

まず追加フィルタ

roundedRectangleGenerator() - CIFilter | Apple Developer Documentation

試して見たところ UIBezierPathinit(roundedRect:cornerRadius:) と同じで rect と radius とを設定して、シェイプの fill color を設定するだけのシンプルなものだった。

transformed(by:highQualityDownsample:)

こちらは追加API

transformed(by:highQualityDownsample:) - CIImage | Apple Developer Documentation

新たに追加されたAPIだけど iOS 10 まで遡って利用可能。ドキュメントは記載が無いがヘッダにコメントが載っていた。

// specifying true or false here will override the context's kCIContextHighQualityDownsample setting.

これまでは CIContext でハイクオリティのダウンサンプリングを利用するかどうかを設定可能だったが、今回のオプションではコンテキスト全体ではなくてスケール処理の一部でハイクオリティを利用するかどうかをコントロール出来る様になりそう。

kCIInputEnableEDRModeKey

追加のオプションキー

kCIInputEnableEDRModeKey - Core Image | Apple Developer Documentation

こちらもまだドキュメントは無いがヘッダにはよれば以下

/** NSNumber (BOOL) : Allows the output to have an Extended Dynamic Range with values greater than 1 possible */

Extended Dynamic Range を有効にするオプションキーらしい。

@available(iOS 12.0, *)
public let kCIInputEnableEDRModeKey: String

現在は String 型になっていて上記の様に宣言されているが、CIRAWFilter 内で宣言されており併記されている他のキーは全て CIRAWFilterOption 型になっているので、このキーも今後のアップデートで CIRAWFilterOption に属する様になるかも知れない。

iOS 13 で追加された Core Image の CIFilter

iOS 13 で何か追加の CIFilter はあったかな?と思って diff を取ってみたら面白かった。
使った出力はワンライナーでこれ

CIFilter.filterNames(inCategory: nil).forEach{print($0)}

CIFilter Changes iOS 12 - iOS 13
https://gist.github.com/86315376f00fa44662f0d841f046e5d2/revisions

iOS 13 beta 1

CIDocumentEnhancer
// CICategoryColorEffect
public protocol CIDocumentEnhancer : CIFilterProtocol {
    @available(iOS 5.0, *)
    var inputImage: CIImage? { get set }
    var amount: Float { get set }
}

f:id:Koze:20190623235940p:plain

CIKMeans

No Header!

CIMorphologyRectangleMaximum
// CICategoryBlur
public protocol CIMorphologyRectangleMaximum : CIFilterProtocol {
    @available(iOS 5.0, *)
    var inputImage: CIImage? { get set }
    var width: Float { get set }
    var height: Float { get set }
}

f:id:Koze:20190624000259p:plain

CIMorphologyRectangleMinimum
// CICategoryBlur
public protocol CIMorphologyRectangleMinimum : CIFilterProtocol {
    @available(iOS 5.0, *)
    var inputImage: CIImage? { get set }
    var width: Float { get set }
    var height: Float { get set }
}

f:id:Koze:20190624000623p:plain

CIPaletteCentroid
// CICategoryColorEffect
public protocol CIPaletteCentroid : CIFilterProtocol {
    @available(iOS 5.0, *)
    var inputImage: CIImage? { get set }
    @available(iOS 5.0, *)
    var paletteImage: CIImage? { get set }
    var perceptual: Bool { get set }
}
CIPalettize
// CICategoryColorEffect
public protocol CIPalettize : CIFilterProtocol {
    @available(iOS 5.0, *)
    var inputImage: CIImage? { get set }
    @available(iOS 5.0, *)
    var paletteImage: CIImage? { get set }
    var perceptual: Bool { get set }
}

iOS 13 beta 2

CIGaborGradients
// CICategoryStylize
public protocol CIGaborGradients : CIFilterProtocol {
    @available(iOS 5.0, *)
    var inputImage: CIImage? { get set }
}

f:id:Koze:20190624002803p:plain

CIKeystoneCorrectionCombined
// CICategoryGeometryAdjustment
public protocol CIKeystoneCorrectionCombined : CIFilterProtocol {
    @available(iOS 5.0, *)
    var inputImage: CIImage? { get set }
    var focalLength: Float { get set }
    var topLeft: CGPoint { get set }
    var topRight: CGPoint { get set }
    var bottomRight: CGPoint { get set }
    var bottomLeft: CGPoint { get set }
}
CIKeystoneCorrectionHorizontal
// CICategoryGeometryAdjustment
public protocol CIKeystoneCorrectionHorizontal : CIFilterProtocol {
    @available(iOS 5.0, *)
    var inputImage: CIImage? { get set }
    var focalLength: Float { get set }
    var topLeft: CGPoint { get set }
    var topRight: CGPoint { get set }
    var bottomRight: CGPoint { get set }
    var bottomLeft: CGPoint { get set }
}
CIKeystoneCorrectionVertical
// CICategoryGeometryAdjustment
public protocol CIKeystoneCorrectionVertical : CIFilterProtocol {
    @available(iOS 5.0, *)
    var inputImage: CIImage? { get set }
    var focalLength: Float { get set }
    var topLeft: CGPoint { get set }
    var topRight: CGPoint { get set }
    var bottomRight: CGPoint { get set }
    var bottomLeft: CGPoint { get set }
}
CIPerspectiveRotate
// CICategoryGeometryAdjustment
public protocol CIPerspectiveRotate : CIFilterProtocol {
    @available(iOS 5.0, *)
    var inputImage: CIImage? { get set }
    var focalLength: Float { get set }
    var pitch: Float { get set }
    var yaw: Float { get set }
    var roll: Float { get set }
}

念の為 diff を取ってみたら beta 1 から beta 2 で追加フィルタがあった!
いずれもドキュメントは存在しないので名前と入力パラメータから機能を推測するしかない。
なのに CIKMeans に至ってはオンラインドキュメントにも Xcode 内にも一切記述が無いという隠れフィルタ!楽しい。

CIFIlter をインスタンス化して取れるプロパティから入出力を調べてみたところ、おそらく以下の様なプロトコル定義になると思う。

CIKMeans
// CICategoryReduction
public protocol CIKMeans : CIFilterProtocol {
    @available(iOS 5.0, *)
    var inputImage: CIImage? { get set }
    var extent: CGRect { get set }
    var means: CIImage? { get set }
    var count: Int { get set }
    var passes: Int { get set }
    var perceptual: Bool { get set }
}

ググってみたところ KMeans ってのは機械学習に出てくる k-means の事だと思われるが CIKMeans フィルタをどう使うかはまだ未調査で不明。
ちなみに CIPaletteCentroidCIPalettize のフィルタの attributes を見ると paletteImage の入力にはこの CIKMeans で得た画像を使用するらしい。

CIGaborGradients についてもググってみたところ機械学習で使われる画像処理 Gabor Filter というものらしい。

CIDocumentEnhancer は名前と効果からドキュメントスキャナ時のフィルタ処理だろうと推測。

CIMorphologyRectangleMinimum CIMorphologyRectangleMaximum については iOS 11 で CIMorphologyMinimum CIMorphologyMaximum CIMorphologyGradient という3つのフィルタが登場しており、WWDC 2017 でこれらのフィルタは depth のマスクを処理するのに良いと紹介されていた。今回追加された2つのフィルタは入力パラメータは少し違うものの用途としては同じ様なものではないかと思われる。

Advances in Core Image: Filters, Metal, Vision, and More - WWDC 2017 - Videos - Apple Developer

とりあえず beta 2 ではこの様な感じで、また今後の beta でも何かしらのフィルタの増減があるかも知れないので余裕があればチェックしてみるかも。

iOS 13 WebKit の変更点

WKWebpagePreferences

WKWebpagePreferences クラスが追加された。
既存では WKPreferences というクラスが WKWebView 全体の設定クラスとして用意されている。
新たに追加された WKWebpagePreferences は基本的にはページ単位での設定クラスになる。

どういった設定ができるのかドキュメントを見てみると
WKWebpagePreferences - WebKit | Apple Developer Documentation

現状できる事は WKWebpagePreferences.ContentMode の設定のみ。
Webページの表示をデスクトップ表示するかモバイル表示するか推奨表示を利用するかを選択する事しかできない模様。

enum ContentMode : Int {
    case desktop
    case mobile
    case recommended
}

WKWebpagePreferences.ContentMode - WKWebpagePreferences | Apple Developer Documentation

使用方法

WKWebViewConfiguration を用いて WKWebView の全体設定としてデフォルトでどのモードで表示するかを設定する事ができる。

@NSCopying var defaultWebpagePreferences: WKWebpagePreferences! { get set }

defaultWebpagePreferences - WKWebViewConfiguration | Apple Developer Documentation

また、WKNavigationDelegate を利用して表示するページ毎にダイナミックに設定を変更する事もできる。

optional func webView(_ webView: WKWebView, 
      decidePolicyFor navigationAction: WKNavigationAction, 
          preferences: WKWebpagePreferences, 
      decisionHandler: @escaping (WKNavigationActionPolicy, WKWebpagePreferences) -> Void)

webView(_:decidePolicyFor:preferences:decisionHandler:) - WKNavigationDelegate | Apple Developer Documentation

iOS だけではなくて macOS でも利用可能なAPIなのでMacアプリでモバイルサイトの表示という事もできてしまいそうではあるが、実際にAPIを試してみたところ

  • iOSアプリでデスクトップ表示は可能
  • Macアプリでモバイル表示の設定はなぜか反映されず*1

という結果になった。(理由は不明)
またサイトによってはおそらくレスポンシブデザインでウィンドウ幅を基準に表示を表示を変えていたり、UserAgent を基準に表示を変えていたりしているため、この WKWebpagePreferences による表示切り替えが効かない場合もあった。
対応サイトでのみ有効という感じになりそう。

WKSnapshotConfiguration

スクリーンショットを撮る時の設定に afterScreenUpdates のオプションが追加された。

var afterScreenUpdates: Bool { get set }

afterScreenUpdates - WKSnapshotConfiguration | Apple Developer Documentation


WebKit の大まかな変更点は以上2つ
あとはエラーコードの追加のみ

WKError - WebKit | Apple Developer Documentation

*1:macOS アプリで WKWebView を使う場合は Capabilities > Sandbox > Outgoing Connection (Client) を有効にしないと通信できないので検証の際には注意

iOS 13 Core Graphics で Tagged PDF の書き出しをサポート

CGPDF 周りの新APIを発見

func CGPDFContextBeginTag(_ context: CGContext, 
                        _ tagType: CGPDFTagType, 
                        _ tagProperties: CFDictionary)

CGPDFContextBeginTag(_:_:_:) - Core Graphics | Apple Developer Documentation

func CGPDFContextEndTag(_ context: CGContext)

CGPDFContextEndTag(_:) - Core Graphics | Apple Developer Documentation

enum CGPDFTagType : Int32

CGPDFTagType - Core Graphics | Apple Developer Documentation

相変わらずオンラインドキュメントが空なので Xcode でSwiftファイルを確認してみたところ以下のコメントの記載が!

/* Tagged PDF Authoring */

この後何十行とコメントが記載されており、PDF 1.7 の仕様で定義されている事やドキュメントのリンクも記載されているので詳細が気になる人はSwiftファイルのコメントや以下のリンクを参照。

http://www.adobe.com/content/dam/Adobe/en/devnet/acrobat/pdfs/pdf_reference_1-7.pdf


Tagged PDF(タグ付きPDF) は Accessibility 対応のPDFで、PDFの中にコンテンツの構造をHTMLに類似したタグ(マークアップ)で示した付加データが入っている。

例えば通常 PDF で表示される文字の情報はフォント、フォントサイズ、描画位置、描画テキストなどの情報が記録されているが、一見1センテンスのまとまった文章に見えても文字毎にバラバラの順序でデータが入っている可能性もある(オーサリングソフトによる)。
また、フォントやフォントサイズの違いによる書類内での意味の違い、例えば表示されているボールド体の文字が文章内での強調なのか、文章の見出しなのか、フォントサイズの小さな文字が注釈なのか、ルビなのか、ページ番号なのかといった情報は記録されていないため、ビューア側でPDFをパースする際にコンテンツ内容をどの様に解釈するかというのはかなり難しくなってくる。

Tagged PDF では描画するコンテンツに意味付けがされるので、スクリーンリーダーでのコンテンツの読み上げ順序やコントロールが改善される。
Accessibility 対応だけではなく、独自ビューアの開発においても Tagged PDF のタグ情報がある事によって同様に読み上げやコントロールの改善が可能になる。

Tagged PDF のタグ情報の読み取りについては相変わらず自前でゴリゴリ実装するしかなさそうだが、PDF の書き出し時にタグ情報を追加できる様になっただけでも前進ではないだろうか。


参考

helpx.adobe.com

helpx.adobe.com

macOS 10.15 AppKit の変更点

AppKit で気になった追加API

NSScreen
var localizedName: String { get }

localizedName - NSScreen | Apple Developer Documentation

これまではスクリーン(macOS ではディスプレイ)に関する情報の取得は CGDisplay 系のAPIで取得していた気がする。
もうちょっと上のレイヤーで簡単にリストアップする事ができる様になりそう。
ちなみに MacBook Pro + Sidecar の環境で実行してみたところ

Build-in Retina Display
AirPlay Display

と表示された。

NSColorSampler

NSColorSampler - AppKit | Apple Developer Documentation

使い方は簡単

NSColorSampler().show { color in
}

これでスポイトツールが表示される。
既存では NSColorPanel を表示してそこからユーザがスポイトツールを選択し使用する事はできたが、NSColorSampler を使うと直接スポイトツールを起動する事ができる。面白い。

NSResponder, NSEvent 周りの changeMode
func changeMode(with event: NSEvent)

changeMode(with:) - NSResponder | Apple Developer Documentation

static var changeMode: NSEvent.EventTypeMask { get }

changeMode - NSEvent.EventTypeMask | Apple Developer Documentation

case changeMode = 38

NSEvent.EventType.changeMode - NSEvent.EventType | Apple Developer Documentation

オンラインドキュメントを見ても Xcode でSwiftファイルを見ても何も載っていないなーと思って探していたら NSResponder の Objective-C header ファイルにコメントが載っていた。

f:id:Koze:20190613122703p:plain

/* Issued in response to a double-tap on the side of the Apple Pencil */ - (void)changeModeWithEvent:(NSEvent *)event API_AVAILABLE(macos(10.15));

macOS で Apple Pencil?
Sidecar 利用時にMacアプリで Apple Pencil のサイドダブルタップが取得できるのだろうかと思い以下の様に、firstRespoder のインスタンスで変更を受け取る実装と NSEvent のモニターメソッドで変更受け取る実装を試してみたけど、Apple Pencil のダブルタップのアクションは受け取れなかった。

    override func changeMode(with event: NSEvent) {
        // not called
        print(event)
    }
    NSEvent.addGlobalMonitorForEvents(matching: .changeMode) { event in
        // not called
        print(event)
    }
    NSEvent.addLocalMonitorForEvents(matching: .changeMode) { event -> NSEvent? in
        // not called
        print(event)
        return event
    }

MonitorForEvents(matching: .any) にするとApple Pencilのタッチ、ドラッグ、圧力などのイベント情報は取れた。ペンサイドのダブルタップのみ反応無し。
まだ beta でちゃんと動いていないのか、何か他の方法での実装が必要なのかも知れない。

追記

Apple Pencil のダブルタップのイベントが取得できなかった件、macOS 10.15 beta 2 で修正された模様。
以下の2箇所で取得できた。

    override func changeMode(with event: NSEvent) {
        // called when double tap
        print(event)
    }
    NSEvent.addGlobalMonitorForEvents(matching: .changeMode) { event in
        // called when double tap
        print(event)
    }

print(event) でイベントをログ出力すると以下の様に type=Translate と記載されているが

NSEvent: type=Translate loc=(174.379,278.68) time=1479.2 flags=0 win=0x100703440 winNum=532 ctxt=0x0

print(event.type.rawValue)rawValue を確認してみたところ値は 38 になっていたので changeMode のイベントで間違いなさそう。

Xcode 11 Core Data の変更点

こっちの記事の派生で Core Data の更新箇所だけ切り出し

koze.hatenablog.jp

Core Data

Default Value オプション
  • Core Data のモデルの String attribute で Default Value の項目が空の場合に Null String を使うか Empty String "" を使うかのチェックボックスオプションが付いた

Xcode 10 では Attribute の Optional 設定のオンオフに関わらず、デフォルト値の設定が空の場合はモデルの生成時に自動で初期値に Empty String が入る仕様になっている。
Xcode 11 ではデフォルト値の設定が空の場合、新しいオプション設定に基づいて初期値に Null String か Empty Stirng が設定される。

ただし試してみたところ、Attribute 設定を Non Optional にして、Default Value を Null String にした場合、モデルの初期化後に何も値を設定しないままDBを保存するとクラッシュしてしまうので、初期値が Null String の場合は Attribute の Optional を強制にしてしまう方が良いのではないかと思った。
ここはまだ初期βなのでフィードバックの余地有り。

なお、Core Data にはモデルクラスの自動コード生成の機能があって、Attribute が Optional かどうかに関わらず Swift 上では以下の様な Optional なプロパティのコードが生成されてしまうため、プロパティに nil を入れて保存するとクラッシュというややこしい事になってしまっている。

extension Event {
    @NSManaged public var title: String?
}

これも生成されるモデルのコードはDBのモデルと揃う様にフィードバックした方が良いと思う。
(Miguration まで考えるとなかなか大変そうではある)

CloudKit
  • Core Data の Configuration に CloudKit を使うかどうかのオプションが付いた

Xcode 11, iOS 13 の Core Data の大きなトピックに CloudKit の同期サポートがある。
詳しくは以下

Using Core Data With CloudKit - WWDC 2019 - Videos - Apple Developer

CloudKit を利用するにチェックを入れるとデフォルト値の設定が必須になったりモデルに変更が必要になるが、おそらく Lightweight Migration 可能(Migration の実装不要)な範囲の変更になると思う。