20200730のiOSに関する記事は10件です。

【Swift 】[String]()とは

var interestId = String

変数宣言でよくみるこの配列の後ろについた()

そいやあこいつ、なんで()がついてんの?

って思ったので、忘備録として記録しておきます。

Swiftでの配列の書式とコードの書き方

空で初期化する場合は下記の書き方をします。
var 配列変数名:[型名] = []
var 配列変数名 = [型名]()

ほーなるほど。

var 配列変数名:[型名] = []

と書いても同じなんですね。

空で初期化する時にこの書き方をするらしいです。

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

[swift]MVCモデルに関して簡潔にまとめました。

MVCモデルとは

Model,View,Controllerの頭文字をとった略称でそれぞれのフォルダを作成してプログラムの構成を他者が見た場合でもわかりやすくする手法。

この手法は多くのプログラマに使用されており、共通のストラクチャーとして認識してもらいやすい。
また、分業して作業する事ができる点や、変更や修正があった場合に影響を受けにくいなどというメリットが存在する。

Model

機能に関する処理を行う。(データの処理を行う)

View

表示と、ユーザーからのアクションを受ける処理を行う。

Controller

機能とアクションを用いてViewに見せる処理を行う。

最後に

今回はMVCモデルに関してかなり簡潔にまとめました。
是非参考にしてください!

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

SwiftとFirebaseでSNSアプリNomadを開発しよう!(第0回)

どんなアプリを作るのか

「SNSアプリをSwiftで作ってみたいけどどのように作ればいいか分からない、、、」
「どのようにアプリをリリースさせればいいか分からない、、、」

このようにお悩みの方は多いと思います。実際私もSwiftを学び始めた頃は自分が理想とするアプリなんて作れるはずがないと思っていました。(単純な画面遷移すら苦労していました笑)
しかし、自分なりにSwiftを学んでみて、この度「Nomad」というアプリを開発し、App Storeにリリースすることができました。Nomadは趣味で繋がれるコミュニティ型のサービスであり、共通の話題さえあればトークできる点が特徴です。
つまり、年齢も経歴も性別も思想も関係なく、誰でも平等な関係でつながれます。これは、昨今問題となっている新型コロナウイルスの流行から着想を得ました。多くの人々が外出自粛を余儀なくされ、閉鎖的な空間にいる現状のなか、「誰かとつながりたい」「ぬくもりを感じたい」と思う人々の欲求に寄り添ったサービスをつくろうと思い、サービスの開発に取り組みました。

このアプリの作り方を共有して、少しでもiOSアプリを開発しようとしている皆さんの参考になれば嬉しいです!
なお、私自身もまだまだ未熟な点が多々あるので、「こういう風にしたらいいんじゃない?」といった指摘がございましたら、どんどんコメントをしていただけると嬉しいです!

では、次回から早速開発をしていきます!

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

iOSアプリ初リリースからこれまでにApp Store Reviewチームからリジェクトされた理由5選

私の最初のアプリ(WalCal)をAppStoreにリリースしてから、約9ヶ月が経ちました。リリースから今まで計7回AppleReviewの審査リジェクトされました。今回はそのリジェクト内容を紹介します。

1. 画像が鮮明ではない

WalCal(ウォーカル)の決済画面に利用可能なクレジットカード会社(VISA, JCB, MasterCard)のロゴ(UIImageView)をStackviewを使い表示しているのですが、これが全体的に伸びてしまったいたためでデザイン面でApple Reviewチームからリジェクトを食らいました。
IMG_2339_iphonesespacegrey_portrait.png

対処法はUIImageViewのContentModeをScaleAspectFillで設定していたのを、scaleAspectFitに変更しました。
IMG_2340_iphonesespacegrey_portrait.png

以下がコードです。

func setupView() {
        //StripeSDK内のクレジットカード画像アセットを使用しています
        let visa = UIImageView(image: STPImageLibrary.visaCardImage())
        let master = UIImageView(image: STPImageLibrary.masterCardCardImage())
        let amex = UIImageView(image: STPImageLibrary.amexCardImage())
        let discover = UIImageView(image: STPImageLibrary.discoverCardImage())
        let jcb = UIImageView(image: STPImageLibrary.jcbCardImage())
        let diners = UIImageView(image: STPImageLibrary.dinersClubCardImage())

        let cardBrands = [visa, master, amex, discover, jcb, diners]
        //修正前のコード
    cardBrands.forEach{($0.contentMode = .scaleAspectFill)}
        //修正後のコード
        cardBrands.forEach{($0.contentMode = .scaleAspectFit)}

        let cardsStackView = UIStackView(arrangedSubviews: cardBrands)
        cardsStackView.axis = .horizontal
        cardsStackView.spacing = 1
        cardsStackView.distribution = .fillEqually

        let cardContainerView = UIView()

        addSubview(dismissButton)
        dismissButton.anchor(top: topAnchor, left: leftAnchor, bottom: nil, right: nil, paddingTop: 10, paddingLeft: 10, paddingBottom: 0, paddingRight: 0, height: 0, width: 0)

        addSubview(cardContainerView)
        cardContainerView.anchor(top: dismissButton.bottomAnchor, left: leftAnchor, bottom: nil, right: rightAnchor, paddingTop: 10, paddingLeft: 30, paddingBottom: 0, paddingRight: 30, height: 50, width: 0)

        cardContainerView.addSubview(cardsStackView)
        cardsStackView.anchor(top: cardContainerView.topAnchor, left: cardContainerView.leftAnchor, bottom: cardContainerView.bottomAnchor, right: cardContainerView.rightAnchor, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, height: 0, width: 0)

        let separatorView1 = UIView()
        separatorView1.backgroundColor = UIColor(white: 0, alpha: 0.2)
        cardContainerView.addSubview(separatorView1)
        separatorView1.anchor(top: nil, left: cardContainerView.leftAnchor, bottom: cardContainerView.bottomAnchor, right: cardContainerView.rightAnchor, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, height: 0.7, width: 0)

        addSubview(stpCardTextField)
        stpCardTextField.anchor(top: cardContainerView.bottomAnchor, left: leftAnchor, bottom: nil, right: rightAnchor, paddingTop: 10, paddingLeft: 30, paddingBottom: 0, paddingRight: 30, height: 0, width: 0)

        addSubview(addButton)
        addButton.anchor(top: stpCardTextField.bottomAnchor, left: leftAnchor, bottom: nil, right: rightAnchor, paddingTop: 20, paddingLeft: 50, paddingBottom: 0, paddingRight: 50, height: 45, width: 0)

        addSubview(chooseLabel)
        chooseLabel.anchor(top: nil, left: leftAnchor, bottom: nil, right: rightAnchor, paddingTop: 0, paddingLeft: 10, paddingBottom: 0, paddingRight: 0, height: 0, width: 0)

        let separator = UIView()
        separator.backgroundColor = UIColor(white: 0, alpha: 0.2)
        addSubview(separator)
        separator.anchor(top: chooseLabel.bottomAnchor, left: leftAnchor, bottom: bottomAnchor, right: rightAnchor, paddingTop: 2, paddingLeft: 5, paddingBottom: 0, paddingRight: 0, height: 0.5, width: 0)
    }

2. ボタンを押しても反応しない

ボタン(UIButton)を設置したあとにそのボタンが機能していなかった時にもらったリジェクトです。
テスト環境ではうまく動いたのに本番では出来ていなかったというのがありました。

3. 機能のデモ動画を用意してくれい

これはリリースから半年過ぎたあたりに、起きた出来事です。
WalCalはホスト登録や、クレジットカードの追加&購入など機能があり、レビューチームは登録しないので、それぞれのデモを用意してくれとの事。
シュミレーターでは不可なので、スクリーン録画でそれをYouTubeにあげて、そのリンクをApp Reviewチームに渡しました。

QuickPlayerで録画して、MOVファイルでも可能です。
参考動画:https://reiver.blog/quicktime/

4. アップルIDサインアップが必須です

2カ月ぶりのアプデをしようとした際に起きたリジェクト内容。
なんとサードパーティーサインインを実装する場合は必ずApple ID sign in を実装しないといけなくなりました。
実装までにちょいと時間がかかりました。

Apple Reviewガイドライン4.8に記載されてあります。
https://developer.apple.com/jp/app-store/review/guidelines/#sign-in-with-apple

5. 最低限機能をつけてくれい

ARKitの実装テストをしてみたく、WalCalのファイル内に入れました。
ただ、アプリでARKitコードは一切実装させなかったのですが、Reviewチームに“ARKitのコードがあるので、ARKitの最低限の機能を満たしてください“と言われてしまいレジェクトです。
対処法はただコードをコメントアウトしました。

Apple Reviewガイドラインの4.2に記載されてあります。
https://developer.apple.com/jp/app-store/review/guidelines/#minimum-functionality

最後にこれからiOSアプリ開発を考えている方へ

初めてアプリを申請した時は審査に通らずリジェクトされるんじゃないかとかなり緊張しました。
そして、しっかりリジェクトされました!笑
初申請の時に3回連続でリジェクトされました。

ただiOSアプリ開発者はほぼ100%リジェクトされた経験があると思うので、皆が通る道だと思ってください。
申請する->リジェクトされる->修正し、再度申請する->リジェクトされる->修正し、再度申請する。->やっと通る

こんな感じです。

審査が通るまで頑張るのみです💪

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

Storyboardに表示されるMinimapを非表示にする

Xcode12からStoryboardでMinimapが表示されるようになりました。
これを非表示にしたいと思ったけれどViewメニューにはありませんでした。

こちらの Editor > Canvas > Minimap が該当コントロールの表示制御。

スクリーンショット 2020-07-30 3.51.43.png

無事非表示にできました。

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

Vision.Frameworkの顔検出を試してみた

はじめに

Vision.Frameworkでの顔検出(+少し顔のランドマーク検出)を試してみて、
取得できるパラメーターや現状やりたかったけどできなかったことをまとめました。
(iOS13まで)

環境

Xcode 11.4.1
Swift 5

今回は、フロントカメラを表示した際に顔検出を行いました。
実装方法は主にこちら(【iOS12対応】Visionを使って顔検出を行う)を参考にさせていただきました。

顔検出について

request: VNDetectFaceRectanglesRequest

顔検出範囲

  • 可能

    • 横顔の場合
    • 目と鼻が出ている場合(口をマスクなどで隠した場合)
    • カメラの上下と顔の上下が一致しない場合
    • 顔が(縦)半分しかカメラに写っていない場合
    • 2mほどカメラから離れた場合
  • 不可能

    • マスクで鼻から下を隠した場合
    • 顔上(下)半分がカメラに写っていない場合

取得できるパラメーター

  • requestRevision

Visionのアルゴリズムのバージョン
1 : iOS11
2 : iOS12

  • confidence

信頼度を示す
最小値が0、最大値が1.0

何度も検証してみましたが、
固定値1.0で返ってくるらしいです。

  • boundingBox = (x, y, height, width)

認識対象を包括する矩形

midX/Yも取得できます。

  • roll(iOS12以上)

首の傾げ具合の角度
30度ずつ取得できる
(Radian表記 30度 = 0.5)

  • yaw(iOS12以上)

顔の横向き角度
45度ずつ取得できる
(Radian表記 45度 = 0.75)

不可能だったこと

  • 顔の上下の角度の取得

AWSRekognisionを並行して使用していたのですが、
そちらを使用すると顔が下(上)を向いている角度を取得できていました。
Visionでは現状そのようなパラメーターは用意されていないようです。

顔のランドマーク検出について

request : VNDetectFaceLandmarksRequest

こちらは軽く試してみました。

取得可能パラメーター

requestRevision / confidence / boundingBoxは顔検出と同じように取得できます。

  • landmarks

顔検出のrequestで使おうとするとnilになるようです。

顔全体で76ポイントを取得しており、
左目、右眉、鼻、輪郭などパーツごとにCGPointの配列を取得できます。
詳しくはAppleDeveloperのドキュメントやこちらをご参照ください。

  • landmarks.confidence

landmarks.confidenceは、
顔が正面の時に約0.9、真横を向くと約0.7が取得できました。

不可能だったこと

  • 写っていないパーツの検出

手で目を隠しているのに、目のポイントが検出されていました。
顔が検出されてしまうと写っていないパーツでも自動補完してくれているようです(?)

写真を撮る時に写っていないパーツがないかチェックしたかったんですが、
現状Visionでは判定できなさそうです。

  • (目を閉じている場合の検出)

がんばれば計算で検出できそうな感じもしました。(参考記事)
CIDetectorを使用すれば検出可能みたいです。

さいごに

今回はVisionでの顔検出について調査してみて、
ざっくりと使えそうなところだけまとめてみました。
iOS14が出ることに伴い、またVisionでできることの範囲は広がりそうですね。

実装方法はとても素晴らしい記事を書いている方がたくさんいらっしゃるので、
参考URLを見て是非試してみてください。

初投稿記事なので、至らぬ点あるかと思いますが、
何かありましたらお気軽にコメントお願いいたします。

参考

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

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

自分的にiPhoneシミュレータでiOS開発する際に欠かせない機能8つ

iOS開発には欠かせないiPhoneシミュレータ。

これが非常に出来がよく、実機で出来ることのほとんどをシミュレートしてくれるので、正直自分は実機よりもこちらを使って開発することが多いです。

Mac上でサクッと動作確認できることはもちろん便利なのですが、ショートカットキーを駆使すればキーボードに手を乗せたままいろいろ操作出来るのがこれまた便利。

また、一見出来なさそうに見えるアレやコレも実はシミュレート出来ちゃいます。

というわけで、個人的に便利だと思っているiPhoneシミュレータの機能をまとめてみました。

1. iPhoneシミュレータを回転させるショートカットキー

「command + →」 で右回転、「command + ←で左回転」 できます。

回転がほぼ必須なiPadアプリを開発するときは特に重宝します。

iPhoneシミュレータを回転させるショートカットキー

2. 実は二本指のピンチも可能

optionキーを押しながらトラックパッドに二本指を置いて片方の指を動かすとピンチできます。 (シミュレータ上に灰色のボタンが二つ表示されたら可能)

さすがにジェスチャ関係は実機を使った方がラクですが、サクッと確認したいときに結構重宝しています。

実はiPhoneシミュレータは二本指のピンチも可能

3. Color Blended Layers

レイヤーが重なっていればいるほど赤く表示してくれる「Color Blended Layers」ですが、 自分は実際のUIパーツのサイズがどうなっているのかを確認するときによく使います。

Screen Shot 2020-07-30 at 14.23.12.png

もちろん、ちゃんと見る場合はヒエラルキーを使った方が良いですが、サクッと確認したいときには重宝しますね。

「メニューバー > Debug > Color Blended Layers」 で表示できます。

4. キーボードを表示・非表示するショートカットキー

UITextFieldもしくはUITextViewにカーソルを置いて、「command + K」 を叩くとキーボードを表示・非表示できます。

なぜか、シミュレータだとキーボードが表示されない場合って結構あるのでこれを覚えておくと便利です。

iPhoneシミュレータでキーボードを表示・非表示するショートカットキー

5. 全てのデータを消去

「メニューバー > Hardware > Erase All Content and Settings...」 で現在使用しているシミュレータの全データを削除できます。常識的なやつですが念の為。

6. ホーム画面に戻るショートカットキー

「shift + command + H」 でホーム画面に戻ることができます。

ちなみに、 「shift + command + H」を二連打すればアプリスイッチャーに遷移できるのでこれまた便利。 捗ります。

iPhoneシミュレータでキーボードを表示・非表示するショートカットキー iPhoneシミュレータでキーボードを表示・非表示するショートカットキー

7. FaceIDもシミュレートできる

実はFaceIDもシミュレートできます。
まあ、FaceIDは実機を使った方がラクなのですが手元に実機がない場合は重宝します。

「メニューバー > Hardware > FaceID」 から。

各項目の意味は以下の通り。

  • Enrolled(FaceIDを使える端末として認識させる)
  • Matching Face(FaceID認証が通ったことをシミュレート)
  • Non-matching Face(FaceID認証が通らないことをシミュレート)

8. 位置情報を指定の場所にする

位置情報も指定できちゃいます。

「メニューバー > Debug > Location > Custom Location...」 で緯度経度を指定できます。

Screen Shot 2020-07-30 at 14.22.09.png

いや、「位置情報の開発はさすがに実機使うよ」という方は多いと思いますが、シミュレータは どこでも 行けるんです。

そう。例えばクパチーノでも。イタリアでも。もちろん北...極でも。

最後に

全部知っている方は少なくないと思いますが、自分がこれからiOS開発を始めるとしたらこれらを知ってると便利だと思うので書いておきます。

もし、この内のいくつかが参考になればこれ幸いです。

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

Xcode11で作成したプロジェクトをiOS12に対応させる方法

はじめに

久しぶりに新規にプロジェクトを作ったのですが、iOS12で動かなかったのでその対応方法です。
Xcode11から SceneDelegate というものがテンプレートで生成されるようになりました。iOS13以降で同一アプリを複数表示するSceneという概念が導入されたことに伴う変更なのですが、iOS12ではSceneの概念がないためクラッシュします。
そのため、iOS12に対応させるためにはひと手間必要になってしまいました。iPhone5sやiPhone6など、まだまだ現役なので対応させない手はありませんよね。

開発環境

  • Xcode11.5
  • Swift

対応内容

AppDelegate

UISceneSession Lifecycleの2つのメソッドをiOS13以降のみビルドされるように修正します。また、SceneDelegateで定義されるようになったUIWindowをAppDelegateに追加します。

AppDelegate.swift
@UIApplicationMain 
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow? // この行を追加

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.

        return true
    }

    // MARK: UISceneSession Lifecycle
    @available(iOS 13.0,*) // この行を追加
    func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
        // Called when a new scene session is being created.
        // Use this method to select a configuration to create the new scene with.
        return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
    }

    @available(iOS 13.0,*) // この行を追加
    func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
        // Called when the user discards a scene session.
        // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
        // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
    }
}

SceneDelegate

SceneDelegateはiOS12に対応していないため、クラスごとiOS13以降にします、

SceneDelegate.swift
@available(iOS 13.0,*)  // この行を追加
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
  :
}

最後に

プロジェクトをゼロから作ることが案外少ないため、久しぶりにテンプレートから作成したらいきなり動かなくてびっくりしました。
iOSは進化が早いというか、後方互換性が切り捨てられるというか、ついていくのが大変ですね。

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

NaturalLanguageフレームワークを使用して日本語のための自然言語処理

Appleには、テキストの分析を支援する NaturalLanguage というフレームワークがあります。この記事は、日本語テキスト分析のための自然言語フレームワークがサポートする、いくつかの機能について取り上げます。

import NaturalLanguage
  • テキストの言語を検知
  • 文を単語区分に分割

この例では、入力テキストは以下のとおりです。

データの保存はiOSアプリの持つ主要な機能です。たとえば、ユーザーが指定した色などの環境設定を保存したり、ウェブサイトのトークンをアプリに保存したり、ToDoリストのアプリを作ってタスクを保存したりすることができます。データをシステムに保存する方法はいくつもあります。

言語検知

このコマンドを実行して、文の言語を検知できます。

func detectLanguage(text: String) {
    let recognizer = NLLanguageRecognizer()
    recognizer.processString(text)
    print("Language: \(recognizer.dominantLanguage?.rawValue ?? "unknown")")
}

結果はこのとおりです。

Language: ja

トークンへの分解

このコマンドで文を単語に分解します。

func tokenize(text: String) {
    let tokenizer = NLTokenizer(unit: .word)
    tokenizer.string = text
    let tokens = tokenizer.tokens(for: text.startIndex ..< text.endIndex)
    var textTokens: [String] = []
    for token in tokens {
        let tokenStartI = token.lowerBound
        let tokenEndI = token.upperBound
        let text = text[tokenStartI ..< tokenEndI]
        textTokens.append(String(text))
    }
    print(textTokens)
}

結果はこのとおりです。

["データ", "の", "保存", "は", "iOS", "アプリ", "の", "持つ", "主要", "な", "機能", "です", "たとえば", "ユーザー", "が", "指定", "し", "た", "色", "など", "の", "環境", "設定", "を", "保存", "し", "たり", "ウェブサイト", "の", "トークン", "を", "アプリ", "に", "保存", "し", "たり", "ToDo", "リスト", "の", "アプリ", "を", "作っ", "て", "タスク", "を", "保存", "し", "たり", "する", "こと", "が", "でき", "ます", "データ", "を", "システム", "に", "保存", "する", "方法", "は", "い", "くつ", "も", "あり", "ます"]

NaturalLanguage フレームワーク内には他の機能もあります。試してみましたが、英語でのみ利用可能なものもありました。より多くの機能が利用可能になりましたら、この記事を更新します。

こちらのウェブページにアクセスすると、私の公開されているQiitaの記事のリストをカテゴリー別にご覧いただけます。

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

【Swift】テキストに取り消し線を付ける

NSAttributeString を使って文字列を装飾するやり方をまとめました。

完成図

実装

@IBOutlet weak var textLabel: UILabel!

private func setTestLabel() {
    // 表示したいテキスト
    let text = "文章の中の一部に取り消し線を付けたい。"
    let attributeString: NSMutableAttributedString =  NSMutableAttributedString(string: text)
    // 全体に共通して付けたいレイアウトを設定
    attributeString.addAttribute(.font,value: UIFont.systemFont(ofSize: 15), range: NSMakeRange(0, attributeString.length))

    // 取り消し線部分の設定
    attributeString.addAttributes([
        .foregroundColor : UIColor.red,
        // 取り消し線の太さを決める
        .strikethroughStyle: 1
    // 取り消し線を反映したい部分を設定
    // NSMakeRange(何文字目から, 何文字間)
    ], range: NSMakeRange(8, 5))
    textLabel.attributedText = attributeString
}

// NSMakeRange(何文字目から, 何文字間)はこんな感じにも書き換えられる
// こちらの方が直感的でわかりやすい
NSString(string: text).range(of: "取り消し線")

これで取り消し線の実装は完了です👌

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