20211008のiOSに関する記事は7件です。

# [Swift] 複数の ビルドTARGET へ Swift Package Manager でライブラリを入れる

[Swift] Swift Package Managerでライブラリを入れる 複数のビルドTARGETにライブラリを入れる際のメモ 1、swift packagesからライブラリを入れる。 iOSアプリ開発にSwift Package Managerを使おう 今回はQGridをプロジェクトへ導入する。 (1) File → Swift packages → add package dependency (2) プロジェクトへ導入したいライブラリのgit url (https://github.com/Q-Mobile/QGrid) を入れる この時点では、ビルドtargetを一つしか選択できない。 2、他のビルドTARGETにも入れる addで導入完了
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Swift] 複数の ビルドTARGET へ Swift Package Manager でライブラリを入れる

[Swift] Swift Package Managerでライブラリを入れる 複数のビルドTARGETにライブラリを入れる際のメモ 1、swift packagesからライブラリを入れる。 iOSアプリ開発にSwift Package Managerを使おう 今回はQGridをプロジェクトへ導入する。 (1) File → Swift packages → add package dependency (2) プロジェクトへ導入したいライブラリのgit url (https://github.com/Q-Mobile/QGrid) を入れる この時点では、ビルドtargetを一つしか選択できない。 2、他のビルドTARGETにも入れる addで導入完了
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

DST Root CA X3 has expired 対策

※注意書き※ 暫定記事です。 DST Root CA X3 の期限切れ Let'sencrypt ユーザの皆さんなら、よくご存知でしょうが、 CA証明書、2021/09/30 に期限が切れてしまったことで様々な影響があると伝えられてきました。明確に「対応がないもの」というのが古いOSであったりするのですが、証明書のコンパチビリティ で示されているような古いOSに限らず 例えば、Windows10あたりでも、自動で入れ替えられたりはしないまま古い証明書が「無効なまま」参照され、VPNなどでは弾かれて(13801エラー)しまいます。 筆者はStrongSwanのKEv2/VPNサービスで「認証エラー」となるため、数時間潰されてしまいました。(証明書が無効ですとエラーが出ればいいのに) Webブラウザ中でなら昔から手慣れたインターフェイスで管理できるのですが、OSはそうでもないことが多いのです。 何をすれば良いのか 接続先サーバの、FQDNに紐付けられている電子署名が、Let'sencrypt で発行されているため、VPNがつながらなくなって困っている人向けの処方です。 Windowsの場合は削除する必要がある(未検証?) certlm.msc :このツールで 証明書ストア にアクセスして確認します。以下の2つがインストールされていて、2020/09/30 に期限を迎えているのであれば、確実につながらないでしょう。 以下の証明書を入れることでチェーン切れを解決します。(Windows/iOS) Root Certficate : ISRG Root X1 (RSA 4096, O = Internet Security Research Group, CN = ISRG Root X1) Self-signed: der -- Intermediate Certificates: Let’s Encrypt R3 (RSA 2048, O = Let's Encrypt, CN = R3) Signed by ISRG Root X1: der それぞれの証明書のインストールについては調べれば解ると思いますので、割愛します。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[SwiftUI] 変数の値をNavigationLinkのdestinationに指定して画面遷移できるようにしたい。

概要 使いまわせるviewは、できるだけ細かく作って、車輪の再開発だけは避けたい!!! と思い、List用のcellのviewを作成。 しかし、cellにあるNavigationLinkのdestinationプロパティの値で怒られ、ハマる。。。 Cannot find type 'Destination' in scopeで怒られ、引数に遷移したいviewを渡せない。。。 struct NavigationLinkView: View { var body: some View { VStack(spacing: 30) { NavigationLinkCell(title: "home", destination: HomeView()) NavigationLinkCell(title: "favorite", destination: FavoriteView()) NavigationLinkCell(title: "test", destination: TestView()) } } } struct NavigationLinkCell: View{ let title: String let destination: Destination var body: some View { NavigationLink(destination: destination) { Text(title) } } } struct HomeView: View { var body: some View { Text("HomeView") } } struct FavoriteView: View { var body: some View { Text("FavoriteView") } } struct TestView: View { var body: some View { Text("TestView") } } 解決策 "Destination : View"  型をつけてやります。 struct NavigationLinkCell<Destination : View>: View{ let title: String let destination: Destination var body: some View { NavigationLink(destination: destination) { Text(title) } } }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[SwiftUI] 変数の値をNavigationLinkのdestinationに指定して遷移できるようにしたい。

概要 使いまわせるviewは、できるだけ細かく作って、車輪の再開発だけは避けたい!!! と思い、List用のcellのviewを作成。 しかし、cellにあるNavigationLinkのdestinationプロパティの値で怒られ、ハマる。。。 Cannot find type 'Destination' in scopeで怒られ、引数に遷移したいviewを渡せない。。。 struct NavigationLinkView: View { var body: some View { VStack(spacing: 30) { NavigationLinkCell(title: "home", destination: HomeView()) NavigationLinkCell(title: "favorite", destination: FavoriteView()) NavigationLinkCell(title: "test", destination: TestView()) } } } struct NavigationLinkCell: View{ let title: String let destination: Destination var body: some View { NavigationLink(destination: destination) { Text(title) } } } struct HomeView: View { var body: some View { Text("HomeView") } } struct FavoriteView: View { var body: some View { Text("FavoriteView") } } struct TestView: View { var body: some View { Text("TestView") } } 解決策 "Destination : View"  型をつけてやります。 struct NavigationLinkCell<Destination : View>: View{ let title: String let destination: Destination var body: some View { NavigationLink(destination: destination) { Text(title) } } }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Swift】URLはStringからデコードできる

偶然気づいたのですが、JSONをデコードする際にURLは直接Stringからデコードできるみたいです。 例えばこういうJSONがあったとします。 let jsonString = """ { "url": "https://example.com/", } """ この時に作成するモデルは struct Example: Decodable { let url: URL } と書く事ができます。let url: Stringとしなくても良いという事です。 試しにデコードしてみます。 let example = try JSONDecoder().decode(Example.self, from: jsonString.data(using: .utf8)!) // Example(url: https://example.com/) print(example) // URL print(type(of: example.url)) どうやらちゃんとURL型にデコードされているみたいです。 今度は不当なStringを与えてみます。 let jsonString = """ { "url": " ", } """ struct Example: Decodable { let url: URL } let example = try JSONDecoder().decode(Example.self, from: jsonString.data(using: .utf8)!) Playground execution terminated: An error was thrown and was not caught: ▿ DecodingError ▿ dataCorrupted : Context ▿ codingPath : 1 element - 0 : CodingKeys(stringValue: "url", intValue: nil) - debugDescription : "Invalid URL string." - underlyingError : nil デコードエラーとなりました。ちゃんと確認はしてませんが、このバリデーションはURL.init(string:)と同じかもしれません。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Dependency Injection

Original.swift class User { } class ApiManager { static let shared = ApiManager() private init() {} func getUsers(completion: @escaping (Result<[User], Error>) -> Void) { let user = User() /* Do task which takes time such as get users over internet. */ completion(.success([user])) } } class Client { func execute() { let api = ApiManager.shared api.getUsers { result in /* do something */ } } } class ClientTest { func testClient() { let client = Client() client.execute() } } For testing purpose, it is not good idea to use real ApiManger instance when unit test is focusing Client class and especially ApiManager does some heavy tasks. So, we want to replace real ApiManager to dummy instance. InstanceInject.swift class User { } class ApiManager { static let shared = ApiManager() // Don't hide initializer so that multiple manager can be created. //private init() {} func getUsers(completion: @escaping (Result<[User], Error>) -> Void) { let user = User() /* Do task which takes time such as get users over internet. */ completion(.success([user])) } } class Client { // add property var api: ApiManager = .shared func execute() { // use referenced singleton manager via property self.api.getUsers { result in /* do something */ } } } class ClientTest { func testClient() { let client = Client() // Inject dummy instance. client.api = ApiManagerStub() // Now execute method uses injected manager during test client.execute() /* do some testing */ } } class ApiManagerStub: ApiManager { override func getUsers(completion: @escaping (Result<[User], Error>) -> Void) { // return immediately completion(.success([])) } } Or, set dependency in initializer. This way is much straight forward. initinjection.swift class Client { private let api: ApiManager init(api: ApiManager = .shared) { self.api = api } func execute() { self.api.getUsers { result in /* do something */ } } } class ClientTest { func testClient() { // Set dummy instance at initialization time. let client = Client(api: ApiManagerStub()) client.execute() /* do some testing */ } } What happens if ApiManager is provided as independent library and cannot modify it? No problem. We can use protocol and class extension to inject. protocolInject.swift protocol Api { func getUsers(completion: @escaping (Result<[User], Error>) -> Void) } extension ApiManager: Api {} class ApiManagerStub: Api { func getUsers(completion: @escaping (Result<[User], Error>) -> Void) { // return immediately completion(.success([])) } } class Client { var api: Api = ApiManager.shared func execute() { self.api.getUsers { result in /* do something */ } } } class ClientTest { func testClient() { let client = Client() // Inject dummy instance. client.api = ApiManagerStub() client.execute() /* do some testing */ } } Other approach is injection by closure. closureInjection.swift typealias Api = (@escaping (Result<[User], Error>) -> Void) -> Void class Client { var getUsers: Api = ApiManager.shared.getUsers(completion:) func execute() { self.getUsers { result in /* do something */ } } } class ClientTest { func testClient() { let client = Client() // Inject dummy instance. client.getUsers = ApiManagerStub().getUsers(completion:) // or directly inject closure client.getUsers = { completion in completion(.success([])) } client.execute() /* do some testing */ } } class ApiManagerStub { func getUsers(completion: @escaping (Result<[User], Error>) -> Void) { // return immediately completion(.success([])) } } Notice (completion:) is not necessary.
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む