20200623のSwiftに関する記事は21件です。

cocoapodsでsdwebimageをinstallしたのにNo such moduleって出るときの対処法

症状

cocoapodsでライブラリ(sdwebimage)をインストールしたのに,importしようとするとNo such moduleとエラーが表示される

対処法

よくあるエラーらしい.いくつか対処法があるらしいが,
私は以下で解決した

ステップ1

ワークスペース(拡張子が.xcworkspaceのやつ)を消す

ステップ2

ターミナルでワークスペースがあった階層まで行きpod installを実行する
これで治るはず
参考
https://stackoverflow.com/questions/54683959/no-such-module-sdwebimage-using-pod

私は治らなかった対処法

https://qiita.com/sukkuuuuu/items/47574f1a4dd3f92aa0bb

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

NSPasteboardで画像を扱う

NSPasteboardの基本

  • 【Apple】URL Reading Options
    • NSPasteboardに関する全体の話。ベースとしてここを参照しています。
    • ※ただしサンプルコードはObjective-Cです。

クリップボードからファイルのURLを取得

// ファイルパスがコピーされている場合を考える
let pasteboard = NSPasteboard.general

// NSImageの扱うUTIを指すfileURLのみ抽出する設定
// 具体的にはprint(NSImage.imageTypes)で確認できる
let classes = [NSURL.self]
let options: [NSPasteboard.ReadingOptionKey : Any] = [.urlReadingFileURLsOnly : true,
                                                      .urlReadingContentsConformToTypes : NSImage.imageTypes]

let canRead = pasteboard.canReadObject(forClasses: classes, options: options)
if canRead {
    let objectsToPaste = pasteboard.readObjects(forClasses: classes,
                                                options: options) ?? []

    if objectsToPaste.count > 0 {
        let fileURL = objectsToPaste[0] as! URL
        if let uti = uti(url: fileURL) {
            // 画像フォーマットを取得できる
            print(uti)  // e.g. UTI: Optional("public.png")
        }
        imageView.image = NSImage(contentsOf: fileURL)  // 出力して確認
    }
} else {
    print("クリップボードにファイルパスはありませんでした")
}

func uti(url: URL) -> String? {
    guard let r = try? url.resourceValues(forKeys: [.typeIdentifierKey]) else {
        return nil
    }
    return r.typeIdentifier
}

クリップボードから画像を取得

NSImageとして取得

  • readObjectsforClassesNSImageと変えるだけでOKです。
// 画像がクリップボードにコピーされている場合
let pasteboard = NSPasteboard.general

let classes = [NSImage.self]
let options = [NSPasteboard.ReadingOptionKey : Any]()

let canRead = pasteboard.canReadObject(forClasses: classes, options: options)
if canRead {
    let objectsToPaste = pasteboard.readObjects(forClasses: classes,
                                                options: options) ?? []

    if objectsToPaste.count > 0 {
        let image = objectsToPaste[0] as! NSImage
        imageView.image = image  // 出力して確認
    }
} else {
    print("クリップボードに画像はありませんでした")
}

NSDataとして取得(画像のフォーマット情報も取得できる)

  • NSPasteboardの機能をうまく利用すると、画像のフォーマット情報を取得することができます。
  • toolinbox/iPicUploader
    • ここのコードを参考にしました。サンプルプロジェクトからJump to Definitionを繰り返せば色々見れるはずです。
    • 今回私のコードはなるべく短くしています。きちんと書く場合は、クラスや関数の分け方を上記ソースから参考にすると良いと思います。
// クリップボードの内容を一旦全て取得する
guard let pasteboardItems = NSPasteboard.general.pasteboardItems else {
    return
}

var myImages = [MyImageInfo]()

for pasteboardItem in pasteboardItems {
    for type in pasteboardItem.types {
        if let data = pasteboardItem.data(forType: type) {
            if let image = NSImage(data: data) {
                myImages.append(MyImageInfo(image: image, uti: type))
            }
        }
    }
}

struct MyImageInfo {
    let image: NSImage
    let uti: NSPasteboard.PasteboardType
}
  • NSPasteboard.PasteboardType
    • しかし足りないものもあって、例えばjpg(public.jpeg)は定数で用意されていないから自分で用意しないといけないかもです。
print(NSPasteboard.PasteboardType.png.rawValue)  // public.png
  • StackOverflow等を検索すると、画像のバイナリの先頭数バイトを見て判断、というアイディアしか見つかりませんでした。
  • (ゴリゴリ系はあまり実装したくないですね)
  • 実際にHex Fiendでバイナリを確認してみると以下の通り。

image
image
image

小ネタ 現在クリップボードを確認する

  • Finderのメニューからクリップボードを表示から確認できます。

- 拡張子も確認できるので、デバッグ時のお供に。

image

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

クリップボードから画像を取得する

NSPasteboardの基本

  • 【Apple】URL Reading Options
    • NSPasteboardに関する全体の話。ベースとしてここを参照しています。
    • ※ただしサンプルコードはObjective-Cです。

クリップボードからファイルのURLを取得

// ファイルパスがコピーされている場合を考える
let pasteboard = NSPasteboard.general

// NSImageの扱うUTIを指すfileURLのみ抽出する設定
// 具体的にはprint(NSImage.imageTypes)で確認できる
let classes = [NSURL.self]
let options: [NSPasteboard.ReadingOptionKey : Any] = [.urlReadingFileURLsOnly : true,
                                                      .urlReadingContentsConformToTypes : NSImage.imageTypes]

let canRead = pasteboard.canReadObject(forClasses: classes, options: options)
if canRead {
    let objectsToPaste = pasteboard.readObjects(forClasses: classes,
                                                options: options) ?? []

    if objectsToPaste.count > 0 {
        let fileURL = objectsToPaste[0] as! URL
        if let uti = uti(url: fileURL) {
            // 画像フォーマットを取得できる
            print(uti)  // e.g. UTI: Optional("public.png")
        }
        imageView.image = NSImage(contentsOf: fileURL)  // 出力して確認
    }
} else {
    print("クリップボードにファイルパスはありませんでした")
}

func uti(url: URL) -> String? {
    guard let r = try? url.resourceValues(forKeys: [.typeIdentifierKey]) else {
        return nil
    }
    return r.typeIdentifier
}

クリップボードから画像を取得

NSImageとして取得

  • readObjectsforClassesNSImageと変えるだけでOKです。
// 画像がクリップボードにコピーされている場合
let pasteboard = NSPasteboard.general

let classes = [NSImage.self]
let options = [NSPasteboard.ReadingOptionKey : Any]()

let canRead = pasteboard.canReadObject(forClasses: classes, options: options)
if canRead {
    let objectsToPaste = pasteboard.readObjects(forClasses: classes,
                                                options: options) ?? []

    if objectsToPaste.count > 0 {
        let image = objectsToPaste[0] as! NSImage
        imageView.image = image  // 出力して確認
    }
} else {
    print("クリップボードに画像はありませんでした")
}

Dataを経由して取得(画像のフォーマット情報も取得できる)

  • NSPasteboardの機能をうまく利用すると、画像のフォーマット情報を取得することができます。
  • toolinbox/iPicUploader
    • ここのコードを参考にしました。サンプルプロジェクトからJump to Definitionを繰り返せば色々見れるはずです。
    • 今回私のコードはなるべく短くしています。きちんと書く場合は、クラスや関数の分け方を上記ソースから参考にすると良いと思います。
// クリップボードの内容を一旦全て取得する
guard let pasteboardItems = NSPasteboard.general.pasteboardItems else {
    return
}

var myImages = [MyImageInfo]()

for pasteboardItem in pasteboardItems {
    for type in pasteboardItem.types {
        if let data = pasteboardItem.data(forType: type) {
            if let image = NSImage(data: data) {
                myImages.append(MyImageInfo(image: image, uti: type))
            }
        }
    }
}

struct MyImageInfo {
    let image: NSImage
    let uti: NSPasteboard.PasteboardType
}
  • NSPasteboard.PasteboardType
    • しかし足りないものもあって、例えばjpg(public.jpeg)は定数で用意されていないから自分で用意しないといけないかもです。
print(NSPasteboard.PasteboardType.png.rawValue)  // public.png
  • StackOverflow等を検索すると、画像のバイナリの先頭数バイトを見て判断、というアイディアしか見つかりませんでした。
  • (ゴリゴリ系はあまり実装したくないですね)
  • 実際にHex Fiendでバイナリを確認してみると以下の通り。

image
image
image

デバッグ時の小ネタ

スクリーンショットの拡張子を変更する

  • デフォルトはpngですが下記の通り変更可能です。
defaults write com.apple.screencapture type jpeg

現在のクリップボードを確認する

  • Finderのメニューからクリップボードを表示から確認できます。
  • 拡張子も確認できるので、デバッグ時のお供に。

image

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Cycle GANをCoreMLモデルに変換

horse2zebra_1.png

*論文:サイクルでつながった敵対的ネットワークを使用するペアになっていない画像から画像への変換

CoreMLに変換することでCycleGAN画像変換をiPhoneアプリで使用できます。

このストーリーでは、TensorFlow CoreのCycleGANチュートリアルモデルを使用します。

最初に、Colaboratoryでチュートリアルモデルをトレーニングします。

colabの以下のセルまでの全てのセルを実行します。

colab
for epoch in range(EPOCHS):
  start = time.time()

  n = 0
  for image_x, image_y in tf.data.Dataset.zip((train_horses, train_zebras)):
    train_step(image_x, image_y)
    if n % 10 == 0:
      print ('.', end='')
    n+=1

  clear_output(wait=True)
  # Using a consistent image (sample_horse) so that the progress of the model
  # is clearly visible.
  generate_images(generator_g, sample_horse)

  if (epoch + 1) % 5 == 0:
    ckpt_save_path = ckpt_manager.save()
    print ('Saving checkpoint for epoch {} at {}'.format(epoch+1,
                                                         ckpt_save_path))

  print ('Time taken for epoch {} is {} sec\n'.format(epoch + 1,
                                                      time.time()-start))

モデルのトレーニングが完了したら、新しいセルを挿入して以下の手順で変換を実行します。

1、TFCoreMLをインストールします。

colab
!pip install --upgrade tfcoreml

2、チェックポイントを復元します。

colab
checkpoint_path = "./checkpoints/train"

ckpt = tf.train.Checkpoint(generator_g=generator_g,
                           generator_f=generator_f,
                           discriminator_x=discriminator_x,
                           discriminator_y=discriminator_y,
                           generator_g_optimizer=generator_g_optimizer,
                           generator_f_optimizer=generator_f_optimizer,
                           discriminator_x_optimizer=discriminator_x_optimizer,
                           discriminator_y_optimizer=discriminator_y_optimizer)

ckpt_manager = tf.train.CheckpointManager(ckpt, checkpoint_path, max_to_keep=5)

# if a checkpoint exists, restore the latest checkpoint.
if ckpt_manager.latest_checkpoint:
  ckpt.restore(ckpt_manager.latest_checkpoint)
  print ('Latest checkpoint restored!!')

3、「saved_model」フォーマットでジェネレータg(これがhorse2zebraジェネレーターです。ジェネレーターfはzebra2horse)を保存します。

colab
generator_g.save './ savedmodel'

4、変換を実行します。

import tfcoreml
input_name = generator.inputs[0].name.split(':')[0]
print(input_name) #Check input_name.
keras_output_node_name = generator_g.outputs[0].name.split(':')[0]
graph_output_node_name = keras_output_node_name.split('/')[-1]
mlmodel = tfcoreml.convert('./savedmodel',
                       input_name_shape_dict={input_name: (1, 256, 256, 3)},
                       output_feature_names=[graph_output_node_name],
                       minimum_ios_deployment_target='13',
                       image_input_names=input_name,
                       image_scale=2/ 255.0,
                       red_bias=-1,
                       green_bias=-1,
                       blue_bias=-1,
                       )
mlmodel.save('./cyclegan.mlmodel')

これで、iOSプロジェクトでCycleGANを使用できます。

import Vision
lazy var coreMLRequest:VNCoreMLRequest = {
   let model = try! VNCoreMLModel(for: cyclegan().model)
   let request = VNCoreMLRequest(model: mode, completionHandler: self.coreMLCompletionHandler0)   
   return request
   }()

let handler = VNImageRequestHandler(ciImage: ciimage,options: [:])   

DispatchQueue.global(qos: .userInitiated).async {   
  try? handler.perform([coreMLRequest])
}

multiArrayを画像として視覚化するには、Hollance氏のCoreML Helpersが非常に便利です。

MultiArrayからImageへの変換 CoreMLHelper

自分でデータセットを用意してトレーニングすれば何2何でも作れます!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

SwiftのKeyPathは結構遅いから気を付けろ

実験

SwiftのKeyPathは普通のプロパティアクセスの100倍遅い。

両方を100万回実行して確認。

var a: Int = 0
class Person {
    var name: String { didSet { a += 1 } }
    init(name: String) { self.name = name }
}

// ドットアクセス
let bobName = "Bob"
let bob = Person(name: bobName)
let start1 = Date()
for _ in 0..<1000000 {
    bob.name = bobName
}
print(Date().timeIntervalSince(start1), "s")

// KeyPathアクセス
let start2 = Date()
let nameKeyPath = \Person.name
for _ in 0..<1000000 {
    bob[keyPath: nameKeyPath] = bobName
}
print(Date().timeIntervalSince(start2), "s")

print(a) // 20000

結果

普通のアクセス KeyPath
0.0066s 0.6208s

KeyPathあまり使わないようにしよう...

PlayGroundでは何故か逆になります。
多分Debug表示の関係でプロパティアクセスに特殊な処理がされてる。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

iPhoneアプリ学習:診断画面

はじめに

某プログラミング学習サイトでの学習記録を記します。

共通操作

・範囲選択:Shiftを押しながらクリック
・複数行コメントアウト:Command /

No1:プロジェクト作成

・Single View

No2:画面

・Main.storyboardを選択
・画面上の三つのアイコンの左端を選ぶ(ViewController)
・Editor > Embed In > Navigation Controllerを選択
 (Navigation Controllerは画面遷移に必要)
・View ControllerのNavigation itemのTitleに題名を入力する
・名前を入力するためのText Fieldとそれを送信するためのButtonを配置する

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

何故かUIScrollViewの正しいサイズが取れない

問題

何故か、UIScrollViewのサイズ(scrollView.bounds.size)が正しい値が取れないことがあった。

値を見てみると、AutoLayoutが作用する前の値が返ってきているようだった。

対処

  • viewDidLayoutSubviewsメソッドを使う
    • 意図したサイズ(AutoLayoutが作用した後のサイズ)を取ることができた。
override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    //UIScrollViewのサイズ取得
}

ただ、viewDidLayoutSubviewsはViewControllerのライフサイクルの一員ではないので、何度でも呼ばれる可能性がある。普通に書いただけで二度呼ばれていたし、画面を回転させた時も呼ばれるのでは?

  • lauoutIfNeededメソッドで強制的にレイアウトを行う
    • 意図したサイズ(AutoLayoutが作用した後のサイズ)を取ることができた。
        //scrollviewの正しいサイズを取得するため、レイアウトを行う。
        self.view.setNeedsLayout()
        self.view.layoutIfNeeded()

        //UIScrollViewのサイズ取得

viewDidLayoutSubviewsは何度も呼ばれる点が不便だったため、lauoutIfNeededを採用した。

更なる課題

UITableView、UICollectionViewなどUIScrollViewのサブクラスではこのような問題は経験上起きないと思うが、何故UIScrollViewでのみこういった問題(オートレイアウトがされていない)が起きるのかよく分からなかった。

参考

https://stackoverflow.com/questions/12527191/ios-autolayout-get-frame-size-width/14147303#14147303

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Swift] Storyboard プロトタイプセルの使い方

プロトタイプセル

Storyboard上でUITableViewやUICollectionViewを設置した際、さらにプロトタイプセルも設置できる。(オブジェクトの追加ボタン(+ボタン)から、table view cellや collection view cellを選ぶ)

セルそのものは、reuseIdentifierを使うことにより、コード上で識別できる。

プロトタイプセルの中身

プロトタイプセル内に自分で設置した部品(例えばUIImageViewやUITextFieldなどなど)は、Story Board上でタグの数値を指定することで、コード上で識別できるようになる。ViewControllerのviewWithTag()メソッドを使う。

参考

[iPhone] UITableView をストーリボードで作る

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

技術的負債を解消するには(iOS開発)

技術的負債がたまるとはどういう状態か

読みにくいコード、複雑なコード(Cruft)は、何も考えなくてもかける為、一応実装のスピードは出る。しかしそれも短期的なもので、時間が経つに連れて負債がたまる。具体的には、ある部分に修正の必要があったり、追加機能が必要な際に、既存のコードを読み解いたりするのに余計な時間がかかってしまう。

どのような方針で対応すべきか

すでにコーディングした部分に修正をくわえる場合

技術的負債を解消するにもコストはかかる。その為、コストとリターンを秤にかけて決定する。

例えば、将来あまり使わなそうなプロジェクトであれば修正をする意味はあまりない。

またプロジェクト内部において、将来あまりいじらない部分のモジュールであれば同じく修正をする意味はあまりなくなる。具体的には、独立性の高い部分のコードなど。

またやるにしてもどの程度やるかの問題がある。全体に対して完璧になるまで修正をすると何ヶ月もかかりかねず、過剰な措置ともなりかねない。他方、全部後回しにしては、前述のようにどんどん負債が大きくなっていってしまう。その為、コーディングする都度、関係する部分を少しずつ直し、自分が見る前よりも少し綺麗なコードにする(ボーイスカウトルール)など、日々少しずつ解消していくのが有効な場合が多いと言える。

これからコーディングをする場合

そもそも技術的負債が発生しないように最初にコーディングするのが一番効率が良い。また知見と技術力さえあれば、そのようなコーディングをしつつ、かかる時間もさほど増やさないようにするのは不可能ではない。

その為、そのような知見を積極的に吸収し、コーディングをするときから積極的に実行していくのが良い。

参考文献

https://note.com/timakin/n/nf7e2a70905d4
https://qiita.com/erukiti/items/9cc7850250268582dde7
http://tlync.hateblo.jp/entry/2014/09/28/025652
https://martinfowler.com/bliki/TechnicalDebt.html
https://medium.com/mop-developers/how-to-manage-technical-debt-961f8f94a623

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Swift: Memory Safety

はじめに

この記事は、下記の記事を見ていきながら Memory Safety について理解していく記事です。

この記事で分かること

  • inout を使う際に気をつけること

Memory Safety

Swiftはデフォルトで安全でない動作が発生するのを防ぎます。

  • 変数は使用される前に初期化される
  • メモリが開放された後はアクセスされない
  • 配列の添字が範囲外でないか確認する

Swiftはメモリを自動で管理しているので、ほとんどの場合は開発者がメモリアクセスについて考える必要はありません。

メモリアクセス

変数への格納や関数に引数として値を渡す際に、コード内でメモリにアクセスします。

// 変数oneが格納されているメモリへの書き込みアクセス
var one = 1

// 変数oneが格納されているメモリからの読み取りアクセス
print("We're number \(one)!")

コード内の異なる領域から同時にメモリ内の同じ場所にアクセスを試みる場合に、競合する可能性があります。
また、メモリ内の同じ場所への複数同時アクセスは、予期せぬ動作や一貫性のない動作が発生する可能性があります。

inout へのアクセスの競合

input とは

input は関数の引数に参照渡しとして値を渡す際に使用する修飾子です。

例として、引数をインクリメントする関数を考えます。
inout の知識ゼロで書くと以下になりますが、コンパイルエラーとなります。

// コンパイルエラー
var num = 1

func increment(number: Int) {
    number += 1 // Left side of mutating operator isn't mutable: 'number' is a 'let' constant
}

エラー文によると、引数は let で定義されていることが分かりました。
つまり、変数numは参照渡しではなく、値渡しになっていることが分かります。

ここで inout を付与します。

// コンパイルエラー
var num = 1

func increment(number: inout Int) {
    number += 1
}

increment(number: num) // Passing value of type 'Int' to an inout parameter requires explicit '&'

再度コンパイルエラー。
inout を付与する場合は、実引数の前に & が必要です。

var num = 1

func increment(number: inout Int) {
    number += 1
}

print(num) // 1
increment(number: &num)
print(num) // 2

inoutとして渡された変数にアクセスできない時

式内で書き込みと読み込みが混在するケース

// コンパイルエラー
var stepSize = 1

func increment(_ number: inout Int) {
    number += stepSize // number: write, stepSize: read
}

increment(&stepSize)
// error: Execution was interrupted, reason: signal SIGABRT.
// The process has been left at the point where it was interrupted, use "thread return -x" to return to the state before expression evaluation.

  • stepSize はグローバル変数
  • 通常なら increment(_:) 内からアクセス可能
  • stepSizeの読み込みと書き込みが同一の式内で混在しており、競合が発生

上記の競合は、一時的な変数を用意して解決することができます。

var stepSize = 1
var copyOfStepSize = stepSize

func increment(_ number: inout Int) {
    number += stepSize
}

increment(&copyOfStepSize)

// 別の変数へ値をコピー (値渡し)
stepSize = copyOfStepSize

print(stepSize) // 2

関数の複数のinput 引数として、同じ変数を渡した時

// コンパイルエラー
func balance(_ x: inout Int, _ y: inout Int) {
    let sum = x + y
    x = sum / 2
    y = sum - x
}
var playerOneScore = 42
var playerTwoScore = 30
balance(&playerOneScore, &playerTwoScore)  // OK
balance(&playerOneScore, &playerOneScore)  // コンパイルエラー
// Inout arguments are not allowed to alias each other
// Overlapping accesses to 'playerOneScore', but modification requires exclusive access; consider copying to a local variable

変数 playerOneScore に対して、複数の書き込みアクセス権が発生し競合してしまうため、コンパイルエラーとなります。

メソッドにおける自己自身へのアクセスの競合

補足: 構造体の mutating 修飾子

構造体で自身のプロパティを変更するメソッドには、mutating 修飾子が必要です。

struct Bird {
    var name: String
    var age: Int

    mutating func updateName(name: String) {
        self.name = name
    }
}

var bird = Bird(name: "hoge", age: 11)
print(bird.name) // hoge
bird.updateName(name: "fuga")
print(bird.name) // fuga

(上の補足にもある通り、) mutating メソッドは、メソッド呼び出しの間は自己への書き込みアクセスを持っています。

例として、下記のようなゲームを考えます。

  • プレイヤーがいる
  • プレイヤーはダメージを受けると減少する health を持つ
  • プレイヤーは特殊能力を使うと現象する energy を持つ
struct Player {
    var name: String
    var health: Int
    var energy: Int

    static let maxHealth = 10
    mutating func restoreHealth() {
        health = Player.maxHealth
    }
}

restoreHealth() メソッドにおいて、selfの書き込みアクセスはメソッドの先頭から始まり、メソッドがreturnされるまで続きます。

下記の shareHealth(with:) メソッドにて、競合が起こる可能性があります。

func balance(_ x: inout Int, _ y: inout Int) {
    let sum = x + y
    x = sum / 2
    y = sum - x
}

struct Player {
    var name: String
    var health: Int
    var energy: Int

    static let maxHealth = 10
    mutating func restoreHealth() {
        health = Player.maxHealth
    }
}

extension Player {
    mutating func shareHealth(with teammate: inout Player) {
        balance(&teammate.health, &health) // ① 引数のインスタンスとメソッド自身を呼ぶインスタンスが同じとなり、書き込みアクセスが競合する
    }
}

var oscar = Player(name: "Oscar", health: 10, energy: 10)
var maria = Player(name: "Maria", health: 5, energy: 10)
oscar.shareHealth(with: &maria)  // OK
maria.shareHealth(with: &maria) // コンパイルエラー①

プロパティへのアクセスの競合

構造体、タプル型、列挙型などの型は、構造体のプロパティやタプルの要素などの複数の要素から構成されています。
これらは値型であるため、値の一部を変更することは値全体が変更されることと同義です。
つまり、プロパティ1つにアクセスするだけでも、値全体へ読み取りアクセスや書き込みアクセスが必要になります。

// コンパイルエラー
func balance(_ x: inout Int, _ y: inout Int) {
    let sum = x + y
    x = sum / 2
    y = sum - x
}

var playerInformation = (health: 10, energy: 20)
var num = 1
// balance(&playerInformation.health, &num) // OK
balance(&playerInformation.health, &playerInformation.energy) // 要素の親が同じタプルなので2つの書き込みアクセスが競合

関数内などのローカルで定義した場合はコンパイルエラーは起こりません。

func balance(_ x: inout Int, _ y: inout Int) {
    let sum = x + y
    x = sum / 2
    y = sum - x
}

struct Player {
    var name: String
    var health: Int
    var energy: Int

    static let maxHealth = 10
    mutating func restoreHealth() {
        health = Player.maxHealth
    }
}

// コンパイルエラー
// var oscar = Player(name: "Oscar", health: 10, energy: 10)
// balance(&oscar.health, &oscar.energy)

func someFunction() {
    var oscar = Player(name: "Oscar", health: 10, energy: 10)
    balance(&oscar.health, &oscar.energy)  // OK
}

Swiftは、コンパイラがメモリへの非排他的アクセスが安全であることを証明できれば、上記のようなメモリ安全なコードを許可します。(ローカルだとコンパイラで面倒を見れるが、グローバルだと見きれない。)

以下の条件が適用される場合、構造体のプロパティへの重複アクセスが安全であることを証明されます。

  • インスタンスのstoredプロパティのみにアクセスしていて、computedプロパティやクラスのプロパティにアクセスしていない
  • 構造体はグローバル変数ではなく、ローカル変数の値
  • 構造体がどのクロージャにもキャプチャされていないか、ノンエスケープクロージャのみにキャプチャされているか

コンパイラがアクセスが安全であることを証明できない場合は、アクセスを許可しません。

まとめ

  • inout を使う時は読み込み・書き込みのアクセス元に気をつけよう。
  • inout が指定された複数の引数をもつ関数に、構造体・タプル型・列挙型などの複数の要素から成る型の要素を同一の親から複数渡した場合、グローバルではコンパイルエラーになり、ローカルだとコンパイラが競合の発生が無いと判断した場合に実行できる。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

初めてのアプリ Swift UIでrealmからデータ変更があった時のUI更新

realmに保存したデータを削除した時にUIへうまく反映されない件(削除されたのに消えないDoneをクリックするとクラッシュ)、今日はコードを微調整したら新しい不具合がありました。Deleteをクリックすると、クラッシュします。

調べると、この記事を参照:https://qiita.com/chocoyama/items/af172b32f492b706c96d

なるほど。realmデータベースの中に保存したデータに変更があってもSwiftが検知できず、知らせて処理するよう書く必要がるなんだとわかりました。

Observeメソッドを使って実現できるらしいですが、自分の場合、まだうまくできませんでした。
またまた同じエラーでクラッシュ。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Present Modallyをdismissした時に遷移前の画面を更新する

備忘録

ios13以降で画面遷移をPresent Modallyにした場合、dismissした時に遷移前の画面が更新されないので、対処法を残しておきます。

対処法1

PresentationをfullScreenにする

Screen Shot 2020-06-23 at 15.52.08.png

対処法2

extension 遷移前ViewControler: UIAdaptivePresentationControllerDelegate {
    func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
        tableView.reloadData()
    }
}
extension 遷移後ViewController {

    override func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) {
        super.dismiss(animated: flag, completion: completion)
        guard let presentationController = presentationController else {
            return
        }
        presentationController.delegate?.presentationControllerDidDismiss?(presentationController)
    }

}

最後に

初心者のため、間違っている可能性があります。
参考までによろしくお願いします。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

iOSでステータスバーの背景色を変える拡張関数(Swift)

はじめに

iOSでは、ステータスバーの背景色を単体でかんたんに変えることができません。
UIViewController#view.backgroundColor を指定するとステータスバーの背景色が変わりますが、同時にビュー全体の背景色も変わってしまいます。

いくつか方法はあるのですが、今回は「上左右をSuperviewに合わせ、下をSafe Areaの上に付けたビュー」を追加することで実現します。
Storyboardを作成するたびに手動でビューを追加するのは手間なので、呼び出すだけでステータスバーの背景色を変えられる拡張関数を実装しました。

環境

  • OS:macOS Mojave 10.14.6
  • Xcode:11.3.1 (11C504)
  • Swift:5.1.3
  • iOS:13.3

実装

UIViewController に拡張関数を追加します。

UIViewController+StatusBar.swift
import UIKit

extension UIViewController {
    private final class StatusBarView: UIView { }

    func setStatusBarBackgroundColor(_ color: UIColor?) {
        for subView in self.view.subviews where subView is StatusBarView {
            subView.removeFromSuperview()
        }
        guard let color = color else {
            return
        }
        let statusBarView = StatusBarView()
        statusBarView.backgroundColor = color
        self.view.addSubview(statusBarView)
        statusBarView.translatesAutoresizingMaskIntoConstraints = false
        statusBarView.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
        statusBarView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
        statusBarView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true
        statusBarView.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor).isActive = true
    }
}

複数回呼ばれてもビューが重ならないよう、処理の最初で StatusBarView があったら剥がすようにしています。

使い方

UIViewControllerviewDidLoad() で色を指定して呼び出すのみです。

FooViewController.swift
final class FooViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        configureView()
    }

    private func configureView() {
        setStatusBarBackgroundColor(.blue)
    }
}

ノッチの有無にかかわらず、ステータスバーの背景色が変わります。

iPhone 8 iPhone 11 Pro Max
Simulator Screen Shot - iPhone 8 - 2020-06-23 at 15.17.25.png Simulator Screen Shot - iPhone 11 Pro Max - 2020-06-23 at 15.27.39.png

参考リンク

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Xcode 12アップデートまとめ!

WWDC2020

今年中もiOS、iPadOS、MacOSなどの新しいOSバージョンと共にXCodeも12が発表されました。
早速、Xcode12のアップデート内容をまとめてみました!!

XCode12

WWDCでApple siliconの発表があったため、 Xcode 12 for macOS Universal Appsと言ったアプリケーションもBETA版として登場しています。

image.png

新機能

タブ表示が追加され、素早いファイルの移動が可能になった

以前にもタブ表示の機能はありましたが、新たに細かい階層でもタブ表示できるようになりました。
Optionキーを押すことで新しいタブが追加されます。
以前のタブよりもだいぶ切り替え表示されるスピードが早いので、かなり便利です。

スクリーンショット 2020-06-23 14.17.30.png

WidgetやAppClipなどの新しく登場したパッケージをサポート

iOS14やiPadOS14からのサポートになるので、早めにいじりたい方はBeta版をインストールしましょう。

新規プロジェクトでLife Cycleという項目が追加

InterfaceでSwiftUIを選択するとLife CycleでSwiftUI Appが選択可能になります。
また、SwiftUIでの開発の仕方ががっつり変わりそうですね。

スクリーンショット 2020-06-23 14.53.11.png

コード補完が高速に

毎回アップデートされていますね。
Xcode11ではSwiftUIの補完が微妙だったのでそこは期待。

SVGがAssetのサポートに追加

やっと、正式にSVGがXcodeでサポートされましたね...
これでアイコンを追加するたびに3枚の画像を追加しなくて良くなります。

サポートOSはiOS13、iPadOS13以降です。

ブレークポイントがドラッグ&ドロップで移動できるようになった

小さなアップデートですが、ありがたい...

Xcodeとシミュレーターを並べて表示できるようになった

スクリーンショット 2020-06-23 14.41.43.png

Swift

guard letのインデントが揃うようになった

guard let x = someOptional,
      let y = anotherOptional else {
  // ...
}

Swift Packages

リソースファイルをパッケージに含められるようになった

バイナリファイルをパッケージに含められるようになった

ついにFirebaseなどのビルド済みフレームワークもSPM対応できそうですね。

SwiftUI

関数ビルダーないでif letswitchが利用可能になった

この機能はXcode11のときから付けて欲しかった...

struct ContentView: View {
    @State var username: String?

    var body: some View {
        Group {
            if let username = username {
                Text("Welcome, \(username)")
            } else {
                Image(systemName: "circle")
            }
        }
    }
}

まとめ

まだ、登場したばかりのXcode12。
今回は開発者目線でバージョンアップしたとわかる箇所ピックアップしてまとめました。
MacOSのデザイン変更によりXcode全体やアイコンも変更されています。

まだまだ、正式リリースには時間があるのでBeta版がアップデートするたびにこの記事もアップデートしていこうと思っています。
読んでいただきありがとうございました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Xcode12アップデートまとめ!

WWDC2020

今年中もiOS、iPadOS、MacOSなどの新しいOSバージョンと共にXCodeも12が発表されました。
早速、Xcode12のアップデート内容をまとめてみました!!

XCode12

WWDCでApple siliconの発表があったため、 Xcode 12 for macOS Universal Appsと言ったアプリケーションもBETA版として登場しています。

image.png

新機能

タブ表示が追加され、素早いファイルの移動が可能になった

以前にもタブ表示の機能はありましたが、新たに細かい階層でもタブ表示できるようになりました。
Optionキーを押すことで新しいタブが追加されます。
以前のタブよりもだいぶ切り替え表示されるスピードが早いので、かなり便利です。

スクリーンショット 2020-06-23 14.17.30.png

WidgetやAppClipなどの新しく登場したパッケージをサポート

iOS14やiPadOS14からのサポートになるので、早めにいじりたい方はBeta版をインストールしましょう。

新規プロジェクトでLife Cycleという項目が追加

InterfaceでSwiftUIを選択するとLife CycleでSwiftUI Appが選択可能になります。
また、SwiftUIでの開発の仕方ががっつり変わりそうですね。

スクリーンショット 2020-06-23 14.53.11.png

コード補完が高速に

毎回アップデートされていますね。
Xcode11ではSwiftUIの補完が微妙だったのでそこは期待。

SVGがAssetのサポートに追加

やっと、正式にSVGがXcodeでサポートされましたね...
これでアイコンを追加するたびに3枚の画像を追加しなくて良くなります。

サポートOSはiOS13、iPadOS13以降です。

ブレークポイントがドラッグ&ドロップで移動できるようになった

小さなアップデートですが、ありがたい...

Xcodeとシミュレーターを並べて表示できるようになった

スクリーンショット 2020-06-23 14.41.43.png

Swift

guard letのインデントが揃うようになった

guard let x = someOptional,
      let y = anotherOptional else {
  // ...
}

Swift Packages

リソースファイルをパッケージに含められるようになった

バイナリファイルをパッケージに含められるようになった

ついにFirebaseなどのビルド済みフレームワークもSPM対応できそうですね。

SwiftUI

関数ビルダーないでif letswitchが利用可能になった

この機能はXcode11のときから付けて欲しかった...

struct ContentView: View {
    @State var username: String?

    var body: some View {
        Group {
            if let username = username {
                Text("Welcome, \(username)")
            } else {
                Image(systemName: "circle")
            }
        }
    }
}

まとめ

まだ、登場したばかりのXcode12。
今回は開発者目線でバージョンアップしたとわかる箇所ピックアップしてまとめました。
MacOSのデザイン変更によりXcode全体やアイコンも変更されています。

まだまだ、正式リリースには時間があるのでBeta版がアップデートするたびにこの記事もアップデートしていこうと思っています。
読んでいただきありがとうございました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Xcode12のアップデート内容をまとめてみた。

WWDC2020

今年中もiOS、iPadOS、MacOSなどの新しいOSバージョンと共にXCodeも12が発表されました。
早速、Xcode12のアップデート内容をまとめてみました!!

XCode12

WWDCでApple siliconの発表があったため、 Xcode 12 for macOS Universal Appsと言ったアプリケーションもBETA版として登場しています。

image.png

新機能

タブ表示が追加され、素早いファイルの移動が可能になった

以前にもタブ表示の機能はありましたが、新たに細かい階層でもタブ表示できるようになりました。
Optionキーを押すことで新しいタブが追加されます。
以前のタブよりもだいぶ切り替え表示されるスピードが早いので、かなり便利です。

スクリーンショット 2020-06-23 14.17.30.png

WidgetやAppClipなどの新しく登場したパッケージをサポート

iOS14やiPadOS14からのサポートになるので、早めにいじりたい方はBeta版をインストールしましょう。

新規プロジェクトでLife Cycleという項目が追加

InterfaceでSwiftUIを選択するとLife CycleでSwiftUI Appが選択可能になります。
また、SwiftUIでの開発の仕方ががっつり変わりそうですね。

スクリーンショット 2020-06-23 14.53.11.png

コード補完が高速に

毎回アップデートされていますね。
Xcode11ではSwiftUIの補完が微妙だったのでそこは期待。

SVGがAssetのサポートに追加

やっと、正式にSVGがXcodeでサポートされましたね...
これでアイコンを追加するたびに3枚の画像を追加しなくて良くなります。

サポートOSはiOS13、iPadOS13以降です。

ブレークポイントがドラッグ&ドロップで移動できるようになった

小さなアップデートですが、ありがたい...

Xcodeとシミュレーターを並べて表示できるようになった

スクリーンショット 2020-06-23 14.41.43.png

Swift

guard letのインデントが揃うようになった

guard let x = someOptional,
      let y = anotherOptional else {
  // ...
}

Swift Packages

リソースファイルをパッケージに含められるようになった

バイナリファイルをパッケージに含められるようになった

ついにFirebaseなどのビルド済みフレームワークもSPM対応できそうですね。

SwiftUI

関数ビルダー内でif letswitchが利用可能になった

この機能はXcode11のときから付けて欲しかった...

struct ContentView: View {
    @State var username: String?

    var body: some View {
        Group {
            if let username = username {
                Text("Welcome, \(username)")
            } else {
                Image(systemName: "circle")
            }
        }
    }
}

まとめ

まだ、登場したばかりのXcode12。
今回は開発者目線でバージョンアップしたとわかる箇所ピックアップしてまとめました。
MacOSのデザイン変更によりXcode全体やアイコンも変更されています。

まだまだ、正式リリースには時間があるのでBeta版がアップデートするたびにこの記事もアップデートしていこうと思っています。
読んでいただきありがとうございました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Swift文字列←→CGFloatやり方によっては誤差が含まれたまま文字列に変換されてしまう

Swift文字列←→CGFloatやり方によっては誤差が含まれたまま文字列に変換されてしまう

目的:"1.1"をCGFloatに変換して、変換したCGFloatの値をもとの文字列"1.1"に戻したい

  1. 文字列からCGFloatに変換
  2. CGFloatから文字列に変換

誤差が含まれて文字列になってしまうやり方があることがわかった
"1.1"をfloatへ(1.100000023841858)これをCGFloatに変換してから文字列へ"1.100000023841858"
32bitアプリか64bitアプリかで違うということらしいので、64bitのCGFloatはdoubleのtypedef

// CGFloatより
/// The native type used to store the CGFloat, which is Float on
/// 32-bit architectures and Double on 64-bit architectures.

ここで注意して欲しいのは、CGFloat(Float("1.1"))としないこと、これは32bitアプリの場合
現在は64bitアプリなのでCGFloat(Double("1.1"))が正解

CGFloatへの変換はNumberFormatterクラスを使う
  • NumberFormatterクラスを使う
    これを使うといい
let strNum = "1.1"
let numberFormatter = NumberFormatter().number(from: strNum) ?? 0.0
let cgFloat = CGFloat(truncating: numberFormatter)
let str = "\(cgFloat)"
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ダークモード対応時にObjective-Cのコードがあったとき

はじめに

歴史のあるiOSアプリのプロジェクトになると、Swift移行が完全でなくObjective-C(以降、objc)のコードが残存していたりするかと思います。

自分の関わるプロジェクトでは、ダークモード対応するぞ!ってなったときに、objcのコードが残っていたので一部objcで対応しました。

コードから直接カラーセットを利用する

Storyboard上のパーツにカラー指定すれば基本的には対応できますが、中にはコード上でカスタムカラーを指定している場合もあります。

Swiftで記述する場合はenumでカラーセットを定義してそれを利用するとか、UIColorのextensionでカスタムカラーを定義する方法があるかと思います。

自分の関わったプロジェクトでは前者の方法で対応していたため、objcでenumを使えませんでした。
objc用で列挙型を定義するのもありかもしれませんが、いずれobjcを撲滅することを考えるとわざわざ定義するのに工数もかけたくありません。
直接呼び出せればいいやって感じです。

その時は以下のようにします。

// ラベルの文字色を決めるとき
textLabel.textColor = [UIColor colorNamed: @"hogehoge"];
// 画像の枠の色を決めるとき
imageView.layer.borderColor = [[UIColor colorNamed: @"hugahuga"] CGColor];

一応、Swiftだとこんな感じになります。

// ラベルの文字色を決めるとき
textLabel.textColor = UIColor(named: "hogehoge") ?? UIColor.black
// 画像の枠の色を決めるとき
imageView.layer.borderColor = UIColor(named: "hugahuga").cgColor ?? UIColor.black.cgColor

意外と簡単にカラーセット呼び出せるんですね。
早くobjc撲滅してSwiftで綺麗にしたい。

ライトモードとダークモードの切り替え時の対応

traitCollectionDidChangeを利用して、モードが切り替わったことを検知して、そのときにカスタムカラーの更新をかけます。

- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection
{
    [super traitCollectionDidChange:previousTraitCollection];

    if (@available(iOS 12.0, *)) {
         UIUserInterfaceStyle currentStyle = self.traitCollection.userInterfaceStyle;
         UIUserInterfaceStyle previousStyle = previousTraitCollection.userInterfaceStyle;

        if (currentStyle != previousStyle) {
            //カスタムカラーの更新処理を記述する
        }
    }
}

Swiftでも基本的に同様の書き方です。

override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
    super.traitCollectionDidChange(previousTraitCollection)

    if #available(iOS 12.0, *) {
        let previousStyle = previousTraitCollection?.userInterfaceStyle
        let currentStyle = traitCollection.userInterfaceStyle

        if previousStyle != currentStyle {
            // カスタムカラーの更新処理を記述する
        }
    }
}

参照

  1. colorNamed: - UIColor | Apple Developer Documentation
  2. iOS13 ダークモード対応
  3. 爆速でiOSアプリのカラー設定をするための`extension`と`enum`
  4. Objective-Cのアプリをダークモード対応した
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Swift5.3の変更点

末尾クロージャ(追加)

複数のトレーリング・クロージャに関する情報をトレーリング・クロージャのセクションに追加しました。
https://docs.swift.org/swift-book/LanguageGuide/Closures.html#ID102

プロトコル(追加)

合成された実装を使用したプロトコルの採用のセクションに、列挙のための Comparable の合成された実装に関する情報が追加されました。
https://docs.swift.org/swift-book/LanguageGuide/Protocols.html#ID627

状況に応じたWhere句(追加)

より多くの場所で一般的な where 節を書くことができるようになり、コンテキストに応じた where 節のセクションが追加されました。
https://docs.swift.org/swift-book/LanguageGuide/Generics.html#ID628

所有されないオプショナル参照(追加)

オプション値での未所有の参照の使用についての情報を持つ、未所有のオプション参照セクションを追加しました。
https://docs.swift.org/swift-book/LanguageGuide/AutomaticReferenceCounting.html#ID625

@main属性(追加)

main セクションに @main 属性に関する情報を追加しました。
https://docs.swift.org/swift-book/ReferenceManual/Attributes.html#ID626

リテラル式(追加)

リテラル式のセクションに #filePath を追加し、#file の説明を更新しました。
https://docs.swift.org/swift-book/ReferenceManual/Expressions.html#ID390

クロージャのエスケープ(更新)

Escaping Closuresセクションを更新し、より多くのシナリオでクロージャが暗黙的に自己を参照できるようになりました。
https://docs.swift.org/swift-book/LanguageGuide/Closures.html#ID546

エラー対処(更新)

Do-CatchとDoステートメントを使用したエラーの処理セクションを更新し、キャッチ句が複数のエラーにマッチするようになりました。
https://docs.swift.org/swift-book/LanguageGuide/ErrorHandling.html#ID541

プロパティ・オブザーバ(更新)

遅延プロパティがオブザーバを持つことができるようになりました。
https://docs.swift.org/swift-book/LanguageGuide/Properties.html#ID262

プロトコル宣言(更新)

プロトコル宣言セクションを更新し、列挙のメンバがプロトコルの要件を満たすことができるようになりました。
https://docs.swift.org/swift-book/ReferenceManual/Declarations.html#ID369

プロパティ・オブザーバ(更新)

ストアド変数オブザーバとプロパティオブザーバのセクションを更新し、ゲッターがオブザーバの前に呼び出される場合について説明しました。
https://docs.swift.org/swift-book/ReferenceManual/Declarations.html#ID359

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

初めてのアプリ トラブル日記 swift--NavigationLinkとForEach/Listの相性悪っ

ユーザが書いたブログのデータをrealmから取得して、タイトルだけを一覧にして、タイトルをNavigationLinkにしてクリックできるようにしたいと思っていました。

一覧はForEachかListループして、クロージャの中でNavigationLinkを書く。下記のようなイメージ:
ForEach(diaries!, id: .self){ diary in
NavigationLink(destination:DiarycontentView(diaries: diary),label:{
Text(diary.diaryTitle)
})
}

シミュレータで確認すると、タイトルをクリックし、DiarycontentViewへ遷移した途端、一覧ページへ戻っちゃう奇妙現象発生でした。(Qiita初心者で画像/動画添付できず許してください)

調べてみてStackoverFlowも色々見ました。先輩にも見てもらって、解決案が二つでした。
①NavigationLinkをクロジャーの中ではなく、ForEachループの外へ移動。
②ForEachの外でさらにScrollViewを使う。 
↑こちらの記事を参照:https://masamichi.me/development/2019/10/21/swiftui-list-multiple-navigationlink.html

②の方法が完璧に解決できました!

けど、こういう記事一覧みたいなのは、NavigationLinkじゃなくて他にもっといいやつがありますよねきっと。みなさんもしご存知でしたら、ぜひお教えいただけますと幸いです!知りたいです!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Swift] iOS13以降で使用可能なAPIまとめ

iOS APIとは?

Appleにより提供されている標準APIです。
意外と知られていない面白い機能などがたくさんあるので、今日はいくつかピックアップして紹介します。

環境

  • Xcode11.1
  • Swift5

Vision(Text Recognition)

68022429-9b05bc00-fce7-11e9-8337-fa71db61583a.gif

概要:
・文字の領域を識別
・文字認識

※英数字の識別しか現状できない

技術資料:
How to use VNRecognizeTextRequest’s optical character recognition to detect text in an image
Text recognition on iOS 13 with Vision, SwiftUI and Combine

サンプルコード:
ScanningDocuments

Apple Document:
https://developer.apple.com/documentation/vision

VisionKit

68005518-e05ec500-fcb8-11e9-802d-4f732efee9df.gif
概要:
・iOS13からNotesアプリに搭載されるOCRの機能を提供(文字認識)
・ドキュメントスキャン
・ドキュメント編集

技術資料:
VisionKitBasics
Scanning documents with Vision and VisionKit on iOS 13

サンプルコード:
VisionKit-Example

Apple Document:
https://developer.apple.com/documentation/visionkit
https://developer.apple.com/documentation/visionkit/vndocumentcameraviewcontrollerdelegate

Core NFC

68223032-60758980-002f-11ea-8fb2-559f9c451b69.gif
概要:
・NFCタグ直接読み取り/書き込み(システムコード指定、暗号化通信可)
・カード固有IDの読み出し
・高機能/複雑な構造を持ったカード・タグの取り扱い
・交通系電子マネーの履歴読み取り
・会員カードの読み取り
・NDEFタグの作成・書き換え
・フィットネス機器などとの双方向の通信
・各種機器の設定
・各種機器のそれなりの容量のデータの読み取り

※ FeliCa Plug, FeliCa Linkその他など

技術資料:
iPhoneでFeliCaを読み取ってみた
iOS13 CoreNFCの使いみちとQRコード、BLEとの比較

サンプルコード:
vCardCoreNFCWriter

ライブラリ:
TRETJapanNFCReader

Apple Document:
https://developer.apple.com/documentation/corenfc

Portrait Effects Matte

68223058-6c614b80-002f-11ea-8e2e-0600ab35794b.png
概要:
・人物の矩形を背景から切り抜き
・人物の矩形と背景の深度測定
・AR表現における回り込み

※現状静止画のみ
※人物のみ

技術資料:
iOS 12のPortrait Matteがすごい/ #iOSDC 2018で登壇します

サンプルコード:
PortraitEffectsMatteSample

Apple Document:
https://developer.apple.com/documentation/avfoundation/avportraiteffectsmatte

Semantic Segmentation Matte

68005658-4fd4b480-fcb9-11e9-800b-c6d109cf0387.jpg
概要:
概要:
・人物の"髪", "肌", "歯"をセグメンテーションする

※現状静止画のみ
※人物のみ

技術資料:
Multi-cam support in iOS 13 allows simultaneous video, photo, and audio capture

Apple Document:
https://developer.apple.com/documentation/avfoundation/avsemanticsegmentationmatte?language=objc

補足:
Portrait Effects Matteと同様の方法でImageDataを操作するが、用意されているメソッドでは今の所実装出来なかった(動かなかった)。 Semantic Segmentation Matteの実装資料も見当たらない。 またApple公式でもSemantic Segmentation Matteの実装について言及している資料が見当たらない。

Core Haptic

68066465-ef5a7b80-fd7b-11e9-8fad-812ae63b4af5.jpg
概要:
・デバイスの振動制御が可能
・細かな振動制御まで可能

技術資料:
iOS13で公開予定の「Core Haptics」を使って、Haptic Feedback (触覚フィードバック) するコードを書いてみた

Apple Document:
https://developer.apple.com/documentation/corehaptics

デプス推定(Apple提供CoreML)

68222674-b85fc080-002e-11ea-99f8-551d11973736.gif
概要:
・iOS11以上であればどのデバイスでも測定可能
・静止画でも動画でも測定可能
・人間以外のオブジェクトも識別可能 ・Depth測定以外(セグメンテーション)なども可能
・Portrait Effects MatteやSemantic Segmentation Matteなど、iOS13以降の標準APIよりかは精度は荒い印象(学習モデルが強化されたら今後の期待大)

技術資料:
DepthPrediction-CoreML

Apple Document:
https://developer.apple.com/jp/machine-learning/models/

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む