20210107のSwiftに関する記事は10件です。

[Swift] スタティックプロパティ(static)を使ってみて分かったこと

はじめに

今回は、スタティックプロパティを理解するためにインスタンスプロパティも一緒に動かしてみたので、
比較しながら理解を深めていけたらなと思います。

試してみたコードの説明

比較のためにインスタンスプロパティaとスタティックプロパティbを用意します。
関数getは、aとbの値の変更内容を表示するためのものです。

struct Sample {
    var a = 0
    static var b = 0

    func get() -> String {
        return "aが\(a)、bが\(Sample.b)"
    }
}

インスタンスプロパティaを変更してみた

//3種類のインスタンスを作成します。
var S1 = Sample()
var S2 = Sample()
var S3 = Sample()

//もちろん結果は同じです。
S1.get()  //"aが0、bが0"
S2.get()  //"aが0、bが0"
S3.get()  //"aが0、bが0"

//S2だけ変更を加えてみます。
S2.a = 3   

//S2.aの部分のみが変更されています。
S1.get()  //"aが0、bが0"
S2.get()  //"aが3、bが0"
S3.get()  //"aが0、bが0"
//変数aにアクセスしようとすると、S1.aかS2.aかS3.aになる。
//インスタンス化したものに紐づいてアクセスするので、値の変更があった場合はそのインスタンスごとに変更になる。
//結果を見てもS2.aだけ変更されている事がわかる。

スタティックプロパティbを変更してみた

Sample.b = 6  

//全てのbが変更されている。
S1.get()  //"aが0、bが6"
S2.get()  //"aが3、bが6"
S3.get()  //"aが0、bが6"
//staticプロパティのbにアスセスするには、Sample.bになる。S1.bとアクセスする事はできない。
//インスタンスではなく、元の型自身に紐づいているプロパティである事がわかる。
//変更結果をみても、元になる型の内容を変更していることになるので、全ての値が変更されている事がわかる。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

SFSymbolsを大きさと色を変えて表示する

はじめに

SFSymbolsを使うことでApple純正アプリでよく見かける画像を簡単にアプリに取り入れることができます。はじめ方についてはこちらで書いています。

let image = let image = UIImage(systemName: "mic")

これだけでマイクアイコンを簡単に貼り付けられます。

大きさと色を変える

let image = UIImage(systemName: "mic", withConfiguration: UIImage.SymbolConfiguration(pointSize: 30, weight: .light, scale: .default))?.withTintColor(.black, renderingMode: .alwaysOriginal)

pointSizeで大きさを、withTintColorで色を変更できます。ボタンを押した際の細かいエフェクトはrenderingModelでいじれます。

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

【Swift】日本語を含むURLを使いたい時はaddingPercentEncodingせよ

知らなくて、APIのコールにつまずいた。

json -> swiftの型生成は quicktype を使った

(NewsAPIからデータを取得しようとしてデコードで失敗した話はこちら
【Swift】NewsAPIで取得したjsonのデコードで失敗して半日潰した話

APIで日本語を含むURLからデータをとってきたい時はaddingPercentEncodingを使う必要があった
image.png

なので日本語を含むURLの場合は以下のように書くべきだった
keywordに日本語が入る

let NewsApiURL="https://newsapi.org/v2/everything?q=\(keyword)&num=3&sortBy=latest&apiKey=\(myApiKey)"
let encodedURL = NewsApiURL.addingPercentEncoding(withAllowedCharacters: NSCharacterSet.urlQueryAllowed)

guard let url = NSURL(string: encodedURL!) else {
    print("無効なURLです。")
    return
}

のようにしてあげたらうまく行った。

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

【Swift】NewsAPIで取得したjsonのデコードで失敗して半日潰した話

前提

swiftの入門書を読んだだけの初学者がニュースアプリを作ってみたレベル。
ニュースはNewsAPIから取得。
取得したjsonは quicktype を使ってswiftのコードを生成した。
image.png

生成されたコード

// This file was generated from JSON Schema using quicktype, do not modify it directly.
// To parse the JSON, add this file to your project and do:
//
//   let welcome = try? newJSONDecoder().decode(Welcome.self, from: jsonData)

import Foundation

// MARK: - Welcome
struct Welcome: Codable {
    let status: String
    let totalResults: Int
    let articles: [Article]
}

// MARK: - Article
struct Article: Codable {
    let source: Source
    let author: String?
    let title, articleDescription: String
    let url: String
    let urlToImage: String
    let publishedAt: Date
    let content: String?

    enum CodingKeys: String, CodingKey {
        case source, author, title
        case articleDescription = "description"
        case url, urlToImage, publishedAt, content
    }
}

// MARK: - Source
struct Source: Codable {
    let id: String?
    let name: String
}

デコード処理に失敗した理由はデータ型のミスだった

設定の問題だったのか特にエラーも吐かず、なんで失敗しているのかわからなかったので、jsonとquicktype生成したコードをひたすらにらめっこしていたら、publishedAtの型が犯人だとわかった

json

// MARK: - Article
struct Article: Codable {
    〜略〜
  "publishedAt": "2020-12-07T14:30:00Z",
    〜略〜
}

生成コード

let publishedAt: Date

修正後

let publishedAt: String

上記の型を修正したら無事にデコードできた。

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

[Swift] Resultのもう一つの使い方?

最初に結論

Resultをcomputed propertyで使うのはどうですか?(※推奨ではなく提案)

Computed propertyでもthrowしたい!

Swiftでは次のようなコードは書けません(Swift 5現在)。

enum E: Error {
  case someError
}

struct S {
  var someProperty: throws Int { // ⛔️ コンパイルできない
    if Bool.random() {
      return 0
    } else {
      throw E.someError
    }
  }
}

なぜならば、そもそもプロパティに対してthrowsというキーワードを使うことができないからです。throwsfunc(またはクロージャ)でしか使えないので、同様のことをしたい場合、普通はこうします:

enum E: Error {
  case someError
}

struct S {
  func someProperty() throws -> Int {
    if Bool.random() {
      return 0
    } else {
      throw E.someError
    }
  }
}

…ところで、Resultを使うという手もありませんかね??

enum E: Error {
  case someError
}

struct S {
  var someProperty: Result<Int, Error> {
    return .init(catching: {
      if Bool.random() {
        return 0
      } else {
        throw E.someError
      }
    })
  }
}

Resultを使うメリット?

特にメリットはありませんけども…あえて挙げるなら:

  • “プロパティはあくまでプロパティであってほしい。funcは使いたくない。”と思う気持ちを実現する。
  • .get()を呼び出すまで評価を遅延できる。

おわりに

単なる思いつきですが、個人的にはpublicじゃない(∴そのモジュール内で完結する)プロパティで使用すると便利な(場面がある)のではないかと考えています。

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

SwiftのDelegateの基本の基

SwiftのDelegateの基本の基

非エンジニアで最近Swiftを勉強している友人に「Delegateって何??」と質問された際を想定し、Delegateの基本についてまとめます。

※主に自身の毎日の復習・学習の機会創出、アウトプットによる知識の定着を目的としております。暖かい目で読んで頂けますと幸いです。

デリゲート(Delegate)

デリゲートは日本語訳は「委譲」です。
委譲は意味としては渡すや任せるです。

swiftでのDelegateも委譲する機能になります!

一言で言うと「あるクラスが、他のクラスのインスタンスに、処理を任せることができる。」と言う説明を多くみます。
※(特定のインスタンスから別のインスタンスへ)
では、具体的に何が何に何を委譲するのか、具体例をみながら確認していきましょう!

1.デリゲートは誰が任せるのか

誰が = 「クラスAが」 
になります。

つまり、あるクラスが自身の処理を任せます。

tableviewであれば「UITableViewクラス」が自身の処理を他人に任せます。

2.デリゲートは何に任せるのか

何に = 「クラスBに」 
になります。

    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.dataSource = self
        tableView.delegate = self
    }

swiftでtableViewを作成するときはこのような表記をすることがよくあるかと思います。

この例では「delegate」を「self」に任せています!
そして、ここでのselfはこのコードを記載している「ViewController」を意味します。
つまり、このコードを記載している「ViewController」に任せることになります!

3.デリゲートは何を任せるのか

何を = 「自身(クラスA)の処理を」 
になります。

そして、この処理のことを具体的に「デリゲートメソッド」と言います。
ですので、正式には「自身のデリゲートメソッド内の処理」を他のクラス・インスタンスに任せる(委譲する)ことになります。

tableviewであれば
swift
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
}

などがデリゲートメソッドに当たります。
※tableviewのデリゲートメソッドは他にもありますが、ここでは割愛

まとめ

・Delegateは「あるクラスAが、クラスBのインスタンスに、処理(クラスAのデリゲートメソッド)を任せることができる。」機能

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

iOS14.2のIDFAまとめ

Xcode Version 12.3 (12C33) で検証

結果

OS isAdvertisingTrackingEnabled trackingAuthorizationStatus uuidString
iOS13 true - 取得できた
iOS13 false - 00000000-0000-0000-0000-000000000000
iOS14.2 true notDetermined 取得できた
iOS14.2 false denied 00000000-0000-0000-0000-000000000000
iOS14.2 true authorized 取得できた
iOS14.2 true denied 00000000-0000-0000-0000-000000000000

その他注意点

  • isAdvertisingTrackingEnabled = false の場合 iOS14以降でもアラートが表示されずに denied 扱い
  • requestTrackingAuthorization の completion は、アラートが表示されなくても呼ばれる
  • アラートで選択肢を選ばずに無理やり電源を切った場合は denied 扱い
  • restricted はよくわかりませんでしたが denied と同じ扱いで良さそう?
  • isAdvertisingTrackingEnabled の値が iOS14 でもちゃんと取れるようになってるっぽい
  • 今の所アラート出さないほうがIDFA取得できちゃいそう...
  • ただ短い期間で動きが変わりがちなので安心できない...
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

iOS14.4のIDFAまとめ

iOS 14.4
Xcode Version 12.3 (12C33) で検証

結果

OS isAdvertisingTrackingEnabled trackingAuthorizationStatus uuidString
iOS13 true - 取得できた
iOS13 false - 00000000-0000-0000-0000-000000000000
iOS14.4 true notDetermined 取得できた
iOS14.4 false denied 00000000-0000-0000-0000-000000000000
iOS14.4 true authorized 取得できた
iOS14.4 true denied 00000000-0000-0000-0000-000000000000

その他注意点

  • isAdvertisingTrackingEnabled = false の場合 iOS14以降でもアラートが表示されずに denied 扱い
  • requestTrackingAuthorization の completion は、アラートが表示されなくても呼ばれる
  • アラートで選択肢を選ばずに無理やり電源を切った場合は denied 扱い
  • restricted はよくわかりませんでしたが denied と同じ扱いで良さそう?
  • isAdvertisingTrackingEnabled の値が iOS14 でもちゃんと取れるようになってるっぽい
  • 今の所アラート出さないほうがIDFA取得できちゃいそう...
  • ただ短い期間で動きが変わりがちなので安心できない...

備考

  • iOS14.2とiOS14.4で調べましたが同じ挙動でした(2021/01/07)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Swift5]コードでダークモード(暗い外観)の適用を回避する方法

実装方法

//ダークモードの適用を回避
self.overrideUserInterfaceStyle = .light

これで常にライトモード(明るい外観)になります。

まとめ

この方法で簡単にダークモードの適用を回避することができます。

しかし、AppleはiOSアプリのダークモード適用を推奨しているので、どこかのタイミングでアプリにダークモード設定を適用させる必要があります。

この方法は、一時的な対応として処理しましょう!

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

iOS14でtrackingAuthorizationStatusのメモ

環境

  • Xcode12.3
  • iOS 14.2 iPhone SE

条件

  1. 端末: 設定>プライバシー>トラッキング>Appからのトラッキング要求を許可 IMG_9760666317E9-1.jpeg
  2. アプリ: トラッキング要求ダイアログ IMG_2264.PNG

トラッキング要求の動き

端末 トラッキング要求 アプリ status
許可 - notDetermined
許可 authorized
拒否 denied
拒否 - denied
許可 denied
拒否 denied

想定通り。
トラッキング要求を出していない状態で、端末設定を拒否から許可に戻すとちゃんとnotDeterminedに戻ります

トラッキング要求を許可後の動き

アプリでトラッキング要求を許可した後に端末設定を拒否にした場合、こんなダイアログが出てくる
トラッキング要求をしていない場合や拒否した場合はダイアログがでない
IMG_729819AB963E-1.jpeg

「Appがトラッキングを続けることを許可する」を選ぶと、こんな画面なので端末で拒否しても取れるのかなと思ったらそんなことはなかった。
IMG_6D17ED26E52E-1.jpeg

再表示するとちゃんとオフになっています
IMG_8F6BE63E2509-1.jpeg

端末設定で再許可時のstatusをそのままにしてくれる動きのようです

ダイアログ status 端末設定で再許可時のstatus
Appがトラッキングを続けることを許可する denied authorized
「Appにトラッキングの停止を要求」 denied denied

端末拒否時のトラッキング要求の動き

また、端末で拒否時にトラッキング要求をするとdeniedが設定されて端末設定を許可に戻してもdeniedのままになります。
トラッキング要求を出していなければnotDeterminedに戻ります

端末拒否時

トラッキング要求 status 端末許可に変更後のstatus
denied notDetermined
denied denied
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む