20190330のSwiftに関する記事は6件です。

[Swift] UIImageViewをスクロースして選択するViewを作る

imageSelecter.gif

UIImageViewをスクロースして選択するViewのソースです。

import UIKit

protocol SelectViewDelegate{
    func selectChanged(image: UIImage)
}

class SelectView : UIScrollView {
    static let kNotToucheTagId = -1
    var images: [UIImage] = [UIImage(named: "01.png")!,
                             UIImage(named: "02.png")!,
                             UIImage(named: "03.png")!,
                             UIImage(named: "04.png")!,
                             UIImage(named: "05.png")!,
                             UIImage(named: "06.png")!,
                             UIImage(named: "11.png")!,
                             UIImage(named: "12.png")!,
                             UIImage(named: "13.png")!,
                             UIImage(named: "14.png")!,
                             UIImage(named: "15.png")!,
                             UIImage(named: "16.png")!,]
    var selectViewDelegate: SelectViewDelegate? = nil
    var imageViews: [UIImageView] = []
    var imageRect:CGRect? = nil

    override func didMoveToSuperview() {
        imageRect = CGRect(x: 0, y: 0, width: self.bounds.height, height: self.bounds.height)
        self.contentSize = CGSize(width: self.bounds.height*CGFloat(images.count), height: self.bounds.height)
        self.isUserInteractionEnabled = true
        self.tag = SelectView.kNotToucheTagId
        setImageViews()
    }

    func setImageViews() {
        let x = self.bounds.height/2
        let y = self.bounds.height/2
        for i in 0..<images.count {
            imageViews.insert(UIImageView(), at: i)
            imageViews[i] = UIImageView(frame: imageRect!)
            imageViews[i].image = images[i]
            imageViews[i].layer.position = CGPoint(x: x+imageRect!.width*CGFloat(i), y:y)
            imageViews[i].isUserInteractionEnabled = true
            imageViews[i].tag = i
            self.addSubview(imageViews[i])
        }
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        if selectViewDelegate == nil {
            return
        }
        for touch: UITouch in touches {
            if touch.view!.tag == SelectView.kNotToucheTagId {
                return
            }
            self.selectViewDelegate!.selectChanged(image: images[touch.view!.tag])
            break
        }
    }
}

利用する側ViewControllerのソースは以下です。

import UIKit

class ViewController: UIViewController, SelectViewDelegate {

    @IBOutlet weak var imageView: UIImageView!
    @IBOutlet weak var selectView: SelectView!

    override func viewDidLoad() {
        super.viewDidLoad()
        let image = UIImage(named: "01.png")
        imageView.image = image
        selectView.selectViewDelegate = self
    }

    func selectChanged(image: UIImage) {
        imageView.image = image
    }
}

Githubに上記ソースをUPしています。
UIImageViewをスクロースして選択するView

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

[CocoaPods] pod install してもimport で使えないとき

oo.xcworkspaceの方で開く

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

try! Swift Tokyo 2019 参加レポート(初日)

try! Swift Tokyo 2019の初日の参加レポートになります。

参加レポート(二日目)

イベント概要

try! Swift はSwift言語での開発における最新の応用事例について集まる国際コミュニティです(公式サイトより)。
iOSに関するものが多いですが基本的にはSwiftであればサーバーでも、当然macOSも対象になります。
Swiftに関して最も大きいイベントの一つと言ってよいイベントです。
Twitter にて最新情報が発信されています。

リンク

こちらに発表資料や文字起こしの情報をまとめて頂いているので、資料についてはそちらを参照していただけると幸いです。

レポート(初日)

スケジュール

Start Time Overview Speaker
10:00 native macOS application、またはAppKitの世界 1024jp
10:25 ⚡️?脱Swiftリテラル初心者 Yuki Aki
10:35 アクセシビリティのためのカラーコントラスト Liz Marley
11:30 Swift Light Jon-Tait Beason
11:55 ⚡️?限定的なimportの明示とその効果 Tomoya Hirano
12:05 protocol/extensionにジェネリクスを入れたい Hikaru Yoshimura
12:30 Keypath入門 Benedikt Terhechte
14:30 テストケースでMemory Leakを発見する Nobuo Saito
14:55 ⚡️?PixarのようなグラフィックをSwiftで実現する Michael Petrie
15:05 ARKitのアプリを作ろう Namrata Bandekar
15:30 ⚡️?Introducing to SourceKit-LSP Ryo Izumi
15:40 Swift Server Update Tom Doron
16:35 SwiftのアプリでCやC++、Objective-Cのフレームワークを使おう Cecilia Humlelu
17:00 ⚡️?MachObfuscator Kamil Borzym
17:10 Siri ShortcutsとNSUserActivityによるエンゲージメント推進 Nic Laughter
17:35 try Prototype! Maxim Cramer

※「⚡️?」は Lightning Talk です(念のため)

native macOS application、またはAppKitの世界

発表者はCotEditorなどを開発した方で、iOSが登場する前からmacOSアプリを開発してきたそうです。
iOSとmacOSのアプリの違い、ネイティブアプリとはどういうことか、というテーマでCotEditorの開発を実例に紹介してくれました。
ネイティブアプリとは、「特定のシステムに向けて設計・ビルドしていること」で、言語やフレームワークということではなく、OSの特性に合わせて、操作性は標準に準拠して作られているべきとしており、AppleのMazipanプロジェクトも単なるエミュレータと断じています。

最近はWeb系の言語でアプリが作れたり、AndroidとiOSでデザインまで合わせる場合があったりもしますが、あらためてネイティブアプリらしさということを意識し、AppleのHuman Interface Guidelinesもチェックしてよいアプリを作るよう心がけねばと思いました。

アクセシビリティのためのカラーコントラスト

色は強力なコミュニケーションツールで、好きな色を使いつつもコントラスト比率を意識してよいアプリにしましょうという主旨の発表です。
HIGにもコントラスト比率についての言及があるそうです。
Color Contrast Checkerというコントラスト比率を計算するツールも紹介してくれています。

Appleの最近の潮流としてダークモードを挙げていて、iOSにも取り入れられるのではないか、その際にはテキストやテーブルの背景色などのデフォルト定義についても変化があるのではないかとのことでした。

Swift Light

Glowforgeという3Dレーザープリンターの会社の方で、プリントするデザインを編集するiOSアプリにてどのようにSwiftを活用しているかというものでした。
込み入った画像周りの処理なので情報がなくて苦労したようです。

protocol/extensionにジェネリクスを入れたい

Scalaエンジニアで型システムを研究していたとのことで、その辺りがテーマになっています。
リストに任意の型を詰め込みたいが、Anyのリストでできるものの型が失われてしまう。
そこで、異なる型を格納できるリスト(=Heterogeneous List(HList))の実装方法について検討したというもの。
HListは中の値と型を対応付けて覚えておくことができるというもので、プロトコルエクステンションでは型を拡張できるので実現できるようですがSwiftの型推論がまだ途上で込み入った実装になってしまうとか。

高度な内容で中盤からほとんどついていけてなかったです。。
しかしながらこういう言語仕様をハックするような話題はワクワクします。
ちなみに、こちらにScalaでの実装についてもまとめているのを見つけました。

Keypath入門

Swift4で追加されたKeypathの紹介。
例として、アプリの設定用structが2つあり、型もそれぞれ異なるがprotocolで編集処理をまとめたい。これをKeypathを用いて解決することをゴールとして話を進めるという流れ。
前提としてKeypathの仕様についての説明をした上で、上記の課題についてコードで順を追って説明して、最後に関連オープンソースライブラリとしてKueryKeyPathKitを紹介してくれました。

Keypathについては知らなかったのであとから調べて何となくは理解できたものの、今回紹介されていたコードは多少消化不良です。。
機会を見つけて使ってみたいです。

テストケースでMemory Leakを発見する

よくクロージャでselfを使う際にweakをいれてなくて循環参照参照してしまう場合があるが、これを規約やコードチェックで防ぎ切ることは難しい。
これをMirror(リフレクション)とweakを使って検出できるようにしようというものでした。
出来たのがXCTAssertNoLeakで、ユニットテストでリークを検出できるようになります。

Swift4.2については言語側の問題で機能しなかったり、Mirrorを使いこなすための工夫など難しい部分がありますが技術的に学びがありました。
例ではViewContorollerを使用していましたが、これはメルカリのMicroViewContorollerの考え方が前提になるのかなと思いました。
(FatViewControllerではXCTestを書くこと自体が厳しいのでは)

ARKitのアプリを作ろう

ARKitを使ったアプリの紹介です。
平面を検知して門を作って表示してくれる「PORTAL」、道路にお絵かきする「ARSKETCH」。
(ストアにはなさそうなのでサンプルかもしれません)
基本的な機能や実装上の注意点だけでなくパフォーマンスについても言及していました。

興味はあるものの実装したことはなかったので面白かったです。
やはりパフォーマンスが重要で、アンカーの制限、フレームレートを落とすなどチューニングが必要になるようです。

Swift Server Update

Swiftでのサーバーアプリケーション開発の近況について話してくれました。
IBM、Vapor、Amazon、Appleなどで使われていて、KituraVaporなどのライブラリがあります。
データベース周りはまだ混在していて、ロギングの一貫性というところにも課題があるようです。
The Swift Server Work Group(SSWG)がIBM、Apple、Vaporにより発表され、DBやネットワーク処理などのライブラリの開発を進めているとのことです。

Kotlinも同じような動きがあったり、スマホアプリ開発にサーバー系の言語の適用する流れもあったり、技術が広がっていて面白いですね。ライブラリも充実してきているとのことで、ちょっとしたサーバーアプリケーションの開発にSwiftを使ってみるとかはやってみたいです。

SwiftのアプリでCやC++、Objective-Cのフレームワークを使おう

C、C++、Objective-Cで作られたライブラリを用途に応じてうまく使っていこうという話です。Swiftから直接C++は呼べないのでObjective-Cを中継するとか、Cのヘッダーが読めないのでmodulemapを作るなどの実践的なテクニックを紹介しています。

アプリの開発を生花に例えて使用する各種言語やライブラリを枝や花に例えていたのが印象的でした。以前C++のライブラリをさらにObjective-Cでラップして部品としてフレームワークを作っていたことがありますが、いろいろな背景やしがらみがある中でギリギリつながって、それでもちゃんと動いているところはすごいなと思ってました(言語仕様やコンパイラ、互換をとる仕組みなどが)。

Siri ShortcutsとNSUserActivityによるエンゲージメント推進

iOS12から追加された、Siri Shortcutsの導入方法についてのチュートリアルの紹介です。
簡単に導入できるということを伝えつつ、Tipsを示してくれていました。

Siri関連はいままでまったく食指が動かず知識もなかったので改めて調べてみましたが、これはなかなか面白い機能ですね。ただ、導入紹介の記事などをみてもあまり利用者はいないようで、もともとSiriが日本人に合うのかというところが課題になりそうです。

try Prototype!

プロトタイプを開発するデザイナーの方による発表で、いくつかの質問から各々が自身のデベロッパーとしてのマインドセットを再構築しましょうというものでした。

  • あなたはなぜデベロッパーなのか
  • 誰のためにコードを書いていますか
  • テクノロジーが変化したときあなたはどうしますか
  • コードを書くときどれくらいの期間使用されるものと考えますか
  • あなたのコードをリリースする際の阻害要因はなんですか
  • どれくらいの頻度でテストしますか

組織やプロダクト、自身の考え方によっても変わってくると思うのでたまには立ち止まって上記の質問について考えを巡らせることも必要と感じました。

try! Swift Tokyo 2019 参加レポート(二日目) に続きます。

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

Swift 5 で String Interpolation をカスタマイズする

String Interpolation とは?

文字列リテラルの中に値を挿入(補完)できる機構のこと。
Swiftでは文字列リテラルの中に \(foo) という書き方でString以外の値を挿入(補完)できます。

  • Interpolation = 挿入・補完の意。
  • 語源的には inter(間) + polire(磨く) で「間に入れて修正する」というニュアンスがあります1
  • String Interpolation は「文字列補間」と訳されるのが一般的です2

let age = 31
print("You are \(age)")

-> You are 31

デフォルトの挙動を変える

extension String.StringInterpolation {
    mutating func appendInterpolation(_ value: Int) {
        appendLiteral("XXX")
    }
}

let int = 10
let string = "number is \(int)"
print(string)

-> number is XXX

引数を渡して出力を変化させる

extension String.StringInterpolation {
    mutating func appendInterpolation(_ value: Date, formatter: DateFormatter) {
        appendLiteral(formatter.string(from: value))
    }
}

let date = Date()
let formatter = DateFormatter()
formatter.dateStyle = .short
formatter.timeStyle = .short
let string = "today is \(date, formatter: formatter)"
print(string)

-> today is 3/30/19, 1:22 PM

独自の型の出力を新しく定義する

struct User {
    let honorific: String
    let name: String
}

extension String.StringInterpolation {
    mutating func appendInterpolation(_ value: User) {
        appendLiteral("\(value.honorific)\(value.name)")
    }
}

let user = User(honorific: "Mr.", name: "Tom")
let string = "user is \(user)"
print(string)

-> user is Mr.Tom

環境

Apple Swift version 5.0 (swiftlang-1001.0.69 clang-1001.0.45.2)
Target: x86_64-apple-darwin18.2.0

参考

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

Xcode10.2への適応で発生したエラー

Xcode10.2になり、Xcodeのアップデートをかけると大きなエラーが発生する。
もともと、Swift3で対応していたので、大幅なジャンプが必要になった。

まずはXcode10.1を平行して使用し、10.1でSwift4.2にアプリ自体をアップデートした。
方法はConvertしただけ。
さらに、使用しているライブラリーを全てアップデートした。

  • Action 3.2.0 -> 3.2.0 (latest version 3.11.0)
  • APIKit 3.2.1 -> 3.2.1 (latest version 4.0.0)
  • Cache 2.2.2 -> 2.2.2 (latest version 5.2.0)
  • CryptoSwift 0.12.0 -> 0.12.0 (latest version 1.0.0)
  • Differentiator 2.0.2 -> 2.0.2 (latest version 3.1.0)
  • Google-Mobile-Ads-SDK 7.38.0 -> 7.38.0 (latest version 7.42.1)
  • KeyboardObserver 2.0.0 -> 2.0.0 (latest version 2.1.0)
  • Nimble 7.3.1 -> 8.0.1 (latest version 8.0.1)
  • NVActivityIndicatorView 4.4.0 -> 4.6.1 (latest version 4.6.1)
  • Quick 1.3.2 -> 2.0.0 (latest version 2.0.0)
  • ReachabilitySwift 4.3.0 -> 4.3.1 (latest version 4.3.1)
  • Result 3.2.4 -> 3.2.4 (latest version 4.1.0)
  • RxCocoa 3.6.1 -> 3.6.1 (latest version 4.4.2)
  • RxDataSources 2.0.2 -> 2.0.2 (latest version 3.1.0)
  • RxOptional 3.2.0 -> 3.2.0 (latest version 3.6.2)
  • RxSwift 3.6.1 -> 3.6.1 (latest version 4.4.2)
  • RxTest 3.6.1 -> 3.6.1 (latest version 4.4.2)
  • SnapKit 3.2.0 -> 3.2.0 (latest version 4.2.0)
  • SwiftLint 0.27.0 -> 0.31.0 (latest version 0.31.0)
  • SwiftyJSON 3.1.4 -> 3.1.4 (latest version 4.2.0)
  • SwiftyStoreKit 0.13.1 -> 0.13.1 (latest version 0.14.2)
  • Willow 3.0.0 -> 3.0.0 (latest version 5.1.0)

げんなりするくらいのライブラリーの多さだが仕方がない。

ビルドの方法によってエラーの種類が違う

エラー出現には2種類のパターンがあることがわかった
ビルド方法の変更は、下記のターゲットに表示される Edit Scheme で変更できる。
Kobito.FmUBnJ.png

表示されたウィンドウの Build Configuration と Debug executable を変更すると、エラー内容が変わる。
このビルド設定はiphoneをつないだ状態でビルドするときに変更していた。対処療法的で理由を明確にしていないのでなんとも根拠にかける。
Kobito.h2teTZ.png

この部分を解説している記事を見つけた。
https://qiita.com/uasi/items/79aecac40f1b2a5f929b

つまり、状況に応じてビルドの設定を変更できるってことらしい。
となると、前任がビルド設定を出し分けていたのかもしれない。

Build Settingの確認

Debug と Relese で違っているのは。Search Path の Framework Search Path と User_Defined が違っている。
そして、Frameworkの方がAPIKitに向いている。
これで
https://stackoverflow.com/questions/55351736/xcode-10-2-swift-5-command-compileswift-failed-while-build-the-program-with-re

Build Configuration が Release で Debug executable のチェックを外した場合

この設定は Archive にする場合に使用していた。
この場合、エラー数は5つでエラーの種類は2種類
どれもライブラリーに対してのエラーである。

Command CompileSwift failed with a nonzero exit code

エラーが出現しているライブラリーは次の通り
- APIKit
- RxSwift
- Cache
- CyptoSwift

※ Debug executable のチェックを入れた状態だとAPIKitのエラーが消える

このエラーはビルドするたびに表示されるライブラリーが増減する。
基本的には上記のライブラリーに表示されるが、、、、
よくよく考えると、このタイミングでライブラリーの修正を個人で行うのは得策ではない。
各ライブラリーが10.2に適応されるのを待つ方が良いかもしれない。

Illegal instruction: 4

  • Cache

Build Configuration が Debug で Debug executable のチェックを入れた場合

この場合は、iphone とつなげて、実機で検証する場合に使用しているビルドモード
エラーの数は19箇所で、種類は4種類
どれもアプリ自体に発生している。

Missing argument for parameter 'configureCell' in call

これは、「RxTableViewSectionedReloadDataSource」のイニシャライズ方法に不備があるようだ。「configureCell」の記述がないことが原因
記述の問題で、こちらの方法を設定しなくてはいけないのかもしれない。
RxDataSourcesライブラリ+UITableViewを使ってMVVMサンプルiOSアプリを作る

この方法だと、Modelを作成しなくてはいけない。
問題はすでにあるHomeViewModelとマージさせる必要があるのかもしれない。

こちらの質問も同じようなことを言っている。
しかし、すでに2017年の話だから、最新バージョンではある程度直っている思うが。
https://github.com/RxSwiftCommunity/RxDataSources/issues/175

こちらが今回エラーが起きている箇所

HomeViewController.swift
fileprivate let dataSource = RxTableViewSectionedReloadDataSource<SectionModel<String, Book>>()

この括弧内に「configureCell」を設定しなくてはいけない。
しかし、なんで、ビルドモードを変更するとこのエラーが消えるのか。

こちらのページの「★4-2. 各々のファイルの役割と処理のポイントに関して」に記載されている状態と同じ状態だがエラーが発生している。

この記事の下に追記されているように記述の順番を変えれば良いんだ。
configureCell の記述を「RxTableViewSectionedReloadDataSource」内に

HomeViewController.swift
//データソースの定義
let dataSource = RxTableViewSectionedReloadDataSource<SectionModel<String, Ramen>>(
    configureCell: { (_, tableView, indexPath, ramens) in
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
        cell.textLabel?.text = ramens.name
        cell.detailTextLabel?.text = ramens.taste
        cell.imageView?.image = ramens.image
        return cell
    })

こちらのエラーはこれで解決した。

Use of unresolved identifier 'HybridCache'

こちらはキャッシュ関連。

Use of undeclared type 'LogMessageWriter'

これは Willow というライブラリーと密接に繋がっているログを表示するためのファイル。
これ以降のエラーは全て同じファイルで発生している。

そもそも、Willowって言うライブラリーは何をしているんだ

Willow とは

このライブラリーの記事自体非常に少ない。
特に日本語の記事は引っかからなかった。マジで前任の奴が変態すぎる。
唯一見つけたのがこちらの記事
https://medium.com/joshtastic-blog/convenient-logging-in-swift-75e1adf6ba7c

冒頭を要約すると、単純にログを便利に取れるって書いてある。
単純にprintで記述すると混乱を生じてしまうから、このライブラリーは便利ぽい。
逆に、そこまで情報が少ないと言うことはこれを使い続ける必要はないだろう。

Use of unresolved identifier 'configuration'

Static member 'AAAA' cannot be used on instance of type 'Logger'

これ以降は同じ内容で、示している部分が違うようだ。
多分、インスタンスの設定が違っているようだ。

  • Static member 'debug' cannot be used on instance of type 'Logger'
  • Static member 'info' cannot be used on instance of type 'Logger'
  • Static member 'event' cannot be used on instance of type 'Logger'
  • Static member 'warn' cannot be used on instance of type 'Logger'
  • Static member 'error' cannot be used on instance of type 'Logger'
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Swift5で起きているVapor3のLeafに関するバグ

私、おそらく日本で唯一、このバグに困っていると思う(2019/3/30現在)のですがこれからググったりする人向けの記事です。Appleが異例とも言えるこの時期にSwiftのバージョンを5に引き上げました。

Swift5ではrow stringsを使用できるようになっています。
これは文字列の頭と語尾に#" "#と区切ることで文字列を表し、今までのバックスラッシュで変数を当てはめていた処理を、""で記述をできる便利なアップデートです。

この処理がVaporの最も重要な機能であるLeafの扱うタグ機能にエラーを引き起こしていると思われます。#(タグ名) でテンプレートをセットしたり、JavaScriptをLeafファイルの部品として扱うことができないようになっています。

GithubのコミュニティやDiscordの方ではアップデートを急いでいるのでSwift5に対応するのも時間の問題と思いますが、解決するまではXcodeのバージョンを下げてSwift4.2で開発やサーバーの稼働をさせることが無難なようです。

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