20211007のSwiftに関する記事は11件です。

APIを利用するModelクラスをテストする

前提 ここでは私自身の備忘録として本記事の執筆に至っています。 仔細な間違い等ございましたらご指摘いただけますと幸いです。 実装すること 今回はXCTestを用いて実際のAPIを叩きそれに対するテストコードを実装してみたいと思います。 実装する内容としてはユーザー名を用いGithubのレポジトリからスター数を5以上のものを返すModelクラスをテストしてみたいと思います。 各クラスのロール     クラス  ロール              GitHubRepository GitHubレポジトリを表現するEntityクラス GitHubAPIClient GitHubのAPIを叩いてデータを取得するAPIクライアント GitHubRepositoryManager 指定したユーザー名のレポジトリ一覧を取得するModelクラス 実際のコード GitHubRepository // GitHubリポジトリを表現するEntityクラス struct GitHubRepository: Codable, Equatable { let id: Int let star: Int let name: String enum CodingKeys: String, CodingKey { case id case star = "stargazers_count" case name } } GitHubAPIClient protocol GitHubAPIClientProtocol { func fetchRepositories(user: String, handler: @escaping([GitHubRepository]?) -> Void) } // GitHubのAPIを叩いてデータを取得するAPIクライアント // 作成したプロトコルに準拠するようにする class GitHubAPIClient: GitHubAPIClientProtocol { // ユーザー名を受け取り、そのユーザーのリポジトリ一覧を取得する // Parameters: // - user: ユーザー名 // - handler: コールバック(引数にリポジトリ一覧が渡される) func fetchRepositories(user: String, handler: @escaping([GitHubRepository]?) -> Void) { let url = URL(string: "http://api.github.com/users/\(user)/repos")! let request = URLRequest(url: url) let task = URLSession.shared.dataTask(with: request) { data, _, error in guard let data = data, error == nil else { handler(nil) return } let repos = try! JSONDecoder().decode([GitHubRepository].self, from: data) DispatchQueue.main.async { handler(repos) } } task.resume() } } GitHubRepositoryManager class GitHubRepositoryManager { // 内部で利用している型をProtocolに変更し、GitHubAPIClientという具体的な型ではなくGitHubAPIClientProtocolというインターフェースにのみ依存させた private let client: GitHubAPIClientProtocol private var repos: [GitHubRepository]? // スターが5以上のリポジトリを返す(未取得の場合は空) var majorRepositories: [GitHubRepository] { guard let repositories = self.repos else { return [] } return repositories.filter({ $0.star >= 5 }) } // 内部でAPIClientを生成している // init() { // self.client = GitHubAPIClient() // } // 内部でGitHubAPIClientを生成せず、コンストラクタ経由で渡せるようにした init(client: GitHubAPIClientProtocol = GitHubAPIClient()) { self.client = client } // 指定されたユーザー名のリポジトリ一覧を読み込み、完了したらコールバックを呼び出す func load(user: String, completion: @escaping() -> Void) { self.client.fetchRepositories(user: user) { repositories in self.repos = repositories completion() } } } 今回はManagerクラスのloadメソッドを呼び出した後で、majorRepositoriesプロパティが正しいリポジトリ一覧(5以上のスター数)を返すことをテストします。 Protocolに準拠させてAPIClientを代替可能にする 今回はよりテストをしやすい環境を作ることを意識し、protocolを利用し、Manager内部でのAPIClientに対する依存関係を解消しています。 このようにすることで、ManagerクラスはAPIClientという具体的な形ではなくAPIClientProtocolというインターフェースにのみ依存することができ、よりテストしやすくなります。 テスト用のモックを作成する 次にテスト用にAPIClientProtocolに準拠したモックを作成します。 モックには以下の2つの機能が必要です。 1.fetchRepositoriesメソッド呼び出し時の引数userを記録する (意図した通りの引数で呼び出されているかを検証するため) 2.任意のGitHubRepositoryの配列をコールバックで返却する (テスト用のデータとして設定した値を返却できるようにするため) SampleTestCodeTests // テスト用にGitHubAPIClientProtocolを準拠したモックを作成する class MockGitHubAPIClient: GitHubAPIClientProtocol { // 返却されたリポジトリ一覧を保持 var returnRepositories: [GitHubRepository] // 呼び出された引数を記録 var argsUser: String? // コンストラクタでテスト用のデータを受け取る init(repositories: [GitHubRepository]) { self.returnRepositories = repositories } // 引数を記録 func fetchRepositories(user: String, handler: @escaping ([GitHubRepository]?) -> Void) { self.argsUser = user handler(self.returnRepositories) } } ここで作成したモックはGitHubAPIClientProtocolに準拠してるのでテスト対象のGitHubRepositoryMangerにそのまま渡せます。 ここまでで、テストコードを記述するのに必要なものが揃いました。 作成したモックを使ってテストする SampleTestCodeTests import XCTest @testable import プロジェクトターゲット名 class SampleTestCodeTests: XCTestCase { override func setUpWithError() throws { // Put setup code here. This method is called before the invocation of each test method in the class. } override func tearDownWithError() throws { // Put teardown code here. This method is called after the invocation of each test method in the class. } func testMajorRepositories() { // テスト用のリポジトリ一覧 (1) let testRepositories: [GitHubRepository] = [ GitHubRepository(id: 0, star: 4, name: ""), GitHubRepository(id: 1, star: 5, name: ""), GitHubRepository(id: 2, star: 6, name: "") ] // モックを作成 (2) let mockClient = MockGitHubAPIClient(repositories: testRepositories) // テスト対象を生成する際にモックを渡す (3) let manager = GitHubRepositoryManager(client: mockClient) //テスト対象のメソッドを呼び出し (4) manager.load(user: "apple") { // 引数の検証 (5) XCTAssertEqual(mockClient.argsUser, "apple") // 結果の検証 (6) XCTAssertEqual(manager.majorRepositories.count, 2) XCTAssertEqual(manager.majorRepositories[0].id, 1) XCTAssertEqual(manager.majorRepositories[1].id, 2) } } } (1)~(3)がテスト用の準備、(4)がテスト対象の呼び出し、(5)、(6)が結果の検証です。 このように、テスト対象が依存するクラスをprotocolに置き換え、テスト用に都合の良いモックを渡せるようにするテクニックは、ユニットテストにおいてよく利用されます。 <参考書籍: iOSアプリ開発自動テストの教科書>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Swift - #colorLiteral使ってカスタマイズのUIColorを定義

はじめに UI部品に色を指定したい場合、↓のようにstoryboardでいじる以外、 コードで指定することもできます。例えば、 サンプル.swift self.view.backgroundColor = UIColor.black .black黒色は内蔵の色なので、UIColor.を入力して、自動的にリストが出てくると思います。↓の感じ でも、もし欲しい色は内蔵にない場合はどうすればいいですか?storyboardでなら、「custom...」が選べるのだが、コードの場合は?? まず UIColorをextensionし、欲しい色の名前を宣言しましょう。 次 #colorLiteral(red: 1, green: 0.8, blue: 0, alpha: 1)をreturnします。 ↓のように sample.swift extension UIColor { static var cusLightYellow: UIColor { return #colorLiteral(red: 1, green: 0.8, blue: 0, alpha: 1) } } 欲しい色の数値わからない?? 大丈夫です!↑のコードを入力したら、↓のように出てきます(色の枠)。 この枠をクリックすると、storyboardみたいなカラーパネルが出てきます。 それでも欲しい色がない?? 下の「Other...」をクリックすると、storyboardの「custom...」のようなものが出てきました!ここで自由に選べます!めでたしめでたし 最後に 普通にコードのカラーリストを確認してみたら、先ほど宣言した「cusLightYellow」が出てきました。 サンプル.swift self.view.backgroundColor = .cusLightYellow
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

UITextField コードですぐに作る為メモ

今回の内容 コード let textfield01 = UITextField() textfield01.frame = CGRect(x: view.frame.maxX / 10, y: view.frame.maxY / 11, width: view.frame.width - (view.frame.maxX / 5), height: 50) textfield01.placeholder = "UITextField01" textfield01.layer.cornerRadius = 10.0 textfield01.layer.borderWidth = 1.0 textfield01.leftView = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: 0)) textfield01.leftViewMode = .always textfield01.layer.borderColor = UIColor.black.cgColor textfield01.backgroundColor = .white textfield01.tag = 0 view.addSubview(textfield01) let textfield02 = UITextField() textfield02.frame = CGRect(x: view.frame.maxX / 10, y: view.frame.maxY / 6.7, width: view.frame.width - (view.frame.maxX / 5), height: 50) textfield02.placeholder = "UITextField02" textfield02.layer.cornerRadius = 10.0 textfield02.layer.borderWidth = 1.0 textfield02.leftView = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: 0)) textfield02.leftViewMode = .always textfield02.layer.borderColor = UIColor.black.cgColor textfield02.backgroundColor = .white textfield02.tag = 0 view.addSubview(textfield02) let textfield03 = UITextField() textfield03.frame = CGRect(x: view.frame.maxX / 10, y: view.frame.maxY / 4.82, width: view.frame.width - (view.frame.maxX / 5), height: 50) textfield03.placeholder = "UITextField03" textfield03.layer.cornerRadius = 10.0 textfield03.layer.borderWidth = 1.0 textfield03.leftView = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: 0)) textfield03.leftViewMode = .always textfield03.layer.borderColor = UIColor.black.cgColor textfield03.backgroundColor = .white textfield03.tag = 0 view.addSubview(textfield03) let textfield04 = UITextField() textfield04.frame = CGRect(x: view.frame.maxX / 10, y: view.frame.maxY / 3.76, width: view.frame.width - (view.frame.maxX / 5), height: 50) textfield04.placeholder = "UITextField04" textfield04.layer.cornerRadius = 10.0 textfield04.layer.borderWidth = 1.0 textfield04.leftView = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: 0)) textfield04.leftViewMode = .always textfield04.layer.borderColor = UIColor.black.cgColor textfield04.backgroundColor = .white textfield04.tag = 0 view.addSubview(textfield04) let textfield05 = UITextField() textfield05.frame = CGRect(x: view.frame.maxX / 10, y: view.frame.maxY / 3.08, width: view.frame.width - (view.frame.maxX / 5), height: 50) textfield05.placeholder = "UITextField05" textfield05.layer.cornerRadius = 10.0 textfield05.layer.borderWidth = 1.0 textfield05.leftView = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: 0)) textfield05.leftViewMode = .always textfield05.layer.borderColor = UIColor.black.cgColor textfield05.backgroundColor = .white textfield05.tag = 0 view.addSubview(textfield05) let textfield06 = UITextField() textfield06.frame = CGRect(x: view.frame.maxX / 10, y: view.frame.maxY / 2.61, width: view.frame.width - (view.frame.maxX / 5), height: 50) textfield06.placeholder = "UITextField06" textfield06.layer.cornerRadius = 10.0 textfield06.layer.borderWidth = 1.0 textfield06.leftView = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: 0)) textfield06.leftViewMode = .always textfield06.layer.borderColor = UIColor.black.cgColor textfield06.backgroundColor = .white textfield06.tag = 0 view.addSubview(textfield06) let textfield07 = UITextField() textfield07.frame = CGRect(x: view.frame.maxX / 10, y: view.frame.maxY / 2.26, width: view.frame.width - (view.frame.maxX / 5), height: 50) textfield07.placeholder = "UITextField07" textfield07.layer.cornerRadius = 10.0 textfield07.layer.borderWidth = 1.0 textfield07.leftView = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: 0)) textfield07.leftViewMode = .always textfield07.layer.borderColor = UIColor.black.cgColor textfield07.backgroundColor = .white textfield07.tag = 0 view.addSubview(textfield07) let textfield08 = UITextField() textfield08.frame = CGRect(x: view.frame.maxX / 10, y: view.frame.maxY / 1.997, width: view.frame.width - (view.frame.maxX / 5), height: 50) textfield08.placeholder = "UITextField08" textfield08.layer.cornerRadius = 10.0 textfield08.layer.borderWidth = 1.0 textfield08.leftView = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: 0)) textfield08.leftViewMode = .always textfield08.layer.borderColor = UIColor.black.cgColor textfield08.backgroundColor = .white textfield08.tag = 0 view.addSubview(textfield08) let textfield09 = UITextField() textfield09.frame = CGRect(x: view.frame.maxX / 10, y: view.frame.maxY / 1.79, width: view.frame.width - (view.frame.maxX / 5), height: 50) textfield09.placeholder = "UITextField09" textfield09.layer.cornerRadius = 10.0 textfield09.layer.borderWidth = 1.0 textfield09.leftView = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: 0)) textfield09.leftViewMode = .always textfield09.layer.borderColor = UIColor.black.cgColor textfield09.backgroundColor = .white textfield09.tag = 0 view.addSubview(textfield09) let textfield10 = UITextField() textfield10.frame = CGRect(x: view.frame.maxX / 10, y: view.frame.maxY / 1.62, width: view.frame.width - (view.frame.maxX / 5), height: 50) textfield10.placeholder = "UITextField10" textfield10.layer.cornerRadius = 10.0 textfield10.layer.borderWidth = 1.0 textfield10.leftView = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: 0)) textfield10.leftViewMode = .always textfield10.layer.borderColor = UIColor.black.cgColor textfield10.backgroundColor = .white textfield10.tag = 0 view.addSubview(textfield10) let textfield11 = UITextField() textfield11.frame = CGRect(x: view.frame.maxX / 10, y: view.frame.maxY / 1.48, width: view.frame.width - (view.frame.maxX / 5), height: 50) textfield11.placeholder = "UITextField11" textfield11.layer.cornerRadius = 10.0 textfield11.layer.borderWidth = 1.0 textfield11.leftView = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: 0)) textfield11.leftViewMode = .always textfield11.layer.borderColor = UIColor.black.cgColor textfield11.backgroundColor = .white textfield11.tag = 0 view.addSubview(textfield11) let textfield12 = UITextField() textfield12.frame = CGRect(x: view.frame.maxX / 10, y: view.frame.maxY / 1.363, width: view.frame.width - (view.frame.maxX / 5), height: 50) textfield12.placeholder = "UITextField12" textfield12.layer.cornerRadius = 10.0 textfield12.layer.borderWidth = 1.0 textfield12.leftView = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: 0)) textfield12.leftViewMode = .always textfield12.layer.borderColor = UIColor.black.cgColor textfield12.backgroundColor = .white textfield12.tag = 0 view.addSubview(textfield12) let textfield13 = UITextField() textfield13.frame = CGRect(x: view.frame.maxX / 10, y: view.frame.maxY / 1.2635, width: view.frame.width - (view.frame.maxX / 5), height: 50) textfield13.placeholder = "UITextField13" textfield13.layer.cornerRadius = 10.0 textfield13.layer.borderWidth = 1.0 textfield13.leftView = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: 0)) textfield13.leftViewMode = .always textfield13.layer.borderColor = UIColor.black.cgColor textfield13.backgroundColor = .white textfield13.tag = 0 view.addSubview(textfield13) let textfield14 = UITextField() textfield14.frame = CGRect(x: view.frame.maxX / 10, y: view.frame.maxY / 1.178, width: view.frame.width - (view.frame.maxX / 5), height: 50) textfield14.placeholder = "UITextField14" textfield14.layer.cornerRadius = 10.0 textfield14.layer.borderWidth = 1.0 textfield14.leftView = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: 0)) textfield14.leftViewMode = .always textfield14.layer.borderColor = UIColor.black.cgColor textfield14.backgroundColor = .white textfield14.tag = 0 view.addSubview(textfield14) 終わり ご指摘、ご質問などありましたら、コメントまでお願い致します。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Carthageで入っている各ライブラリのSwiftバージョンを洗い出すシェル芸

ABI Stability & Module Stability 対応しているライブラリはSwiftのバージョンを上げて carthage bootstrap --cache-builds してもキャッシュが効いてビルドが走らないが、その関係で複数のSwiftバージョンでビルドされたライブラリが混在する結果になる。 そこで、各ライブラリがどのバージョンでビルドされているのかが知りたくてシェルを書いた。 $ find Carthage/Build -name "*.version" -exec /usr/local/bin/jq '.iOS[] | [.name, .swiftToolchainVersion] | join(": ")' {} \; | cat | uniq | sed -r 's/\"//g' result(例、一部抜粋) KeychainAccess: 5.4.2 (swiftlang-1205.0.28.2 clang-1205.0.19.57) SVProgressHUD: OHHTTPStubs: 5.5 (swiftlang-1300.0.31.1 clang-1300.0.29.1) Device: 5.5 (swiftlang-1300.0.31.1 clang-1300.0.29.1) Alamofire: 5.5 (swiftlang-1300.0.31.1 clang-1300.0.29.1) RxBlocking: 5.5 (swiftlang-1300.0.31.1 clang-1300.0.29.1) RxCocoa: 5.5 (swiftlang-1300.0.31.1 clang-1300.0.29.1) RxRelay: 5.5 (swiftlang-1300.0.31.1 clang-1300.0.29.1) RxSwift: 5.5 (swiftlang-1300.0.31.1 clang-1300.0.29.1) RxTest: 5.5 (swiftlang-1300.0.31.1 clang-1300.0.29.1) APIKit: 5.4.2 (swiftlang-1205.0.28.2 clang-1205.0.19.57) CryptoSwift: 5.4.2 (swiftlang-1205.0.28.2 clang-1205.0.19.57) FBSnapshotTestCase: 5.5 (swiftlang-1300.0.31.1 clang-1300.0.29.1) MultipartFormDataParser: 5.5 (swiftlang-1300.0.31.1 clang-1300.0.29.1) SDWebImage: SDWebImageMapKit: ※空白になっているのはObj-C製なのでswiftToolchainVersionが存在しない
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Unity] iOS NativePluginの実装の仕方

はじめに Androidに引き続き、iOS側でもNativePluginの作成方法をまとめました。 ここでは、UnityでiOSのNativeアラートを表示させるまでの忘却録です。 Unity向けのiOS Pluginは作り方は人によって違うと思いますが、 今回は『UnityのiOSビルド結果であるXcodeプロジェクト上からコードを編集しました。』 もっと効率の良いやり方があればご教授下さい><; Android版↓ 準備 macOS Catalina: 10.15.7 Unity 2018.4.19f Xcode12.4 Swift4.0 UnityとiOS Pluginの構成 Unityから書き出されるiOS関連のファイルはObjective-CベースなのでSwiftを呼び出す設定が必要です。 SwiftからObjective-Cのクラスに呼ぶには、宣言されてるヘッダーファイルを特定のヘッダーファイルでimportして使用します。 今回はObjective-C++のコードを経由させます。 呼び出しの簡易図は下記。 UnityのC#がインターフェース(.csファイル) ↑↓ ↓↑ iOSネイティブ Objective-C++ Cインターフェース(.mmファイル) ↓↑ ↓↑ iOSネイティブ Swiftコード(.swiftファイル) Unity側の対応(呼び出し方法)サンプル ボタンを押下してアラート表示は、Androidの時の対応と同様な構成にしています。 ここでのポイントは下記です。 ①、[DllImport("__Internal")]属性を付けること。 ネイティブプラグイン参照 ButtonView.cs using System.Runtime.InteropServices; using UnityEngine; public class ButtonView : MonoBehaviour { #if UNITY_IOS && !UNITY_EDITOR [DllImport("__Internal")] private static extern void _showAlert(); #endif public void ShowNativeDialog() { #if UNITY_IOS && !UNITY_EDITOR _showAlert(); #endif } } Unity上でSwiftファイル、Objective-C++のファイルを準備 Assets→Plugin→iOSディレクトリが無ければ作成します。 ここにNativePluginのファイルを置きます。 AlertPlugin.swift、AlertPlugin.mmファイルを作成。中身は空です。 ビルド周りのEditor拡張が必要 やることは下記です。 ①、Swiftのバージョン指定する(今回はSwift4.0) ②、Objective-C Bridging Headerの設定 ③、Objective-C Generated Interface Header Nameの設定 上記を設定していきますが、便利なPluginが既に用意されてるのでこちらを使用していきます。 ビルド時に自動で設定してくれます。ありがたや! unity-swift.unitypackageをDownloadしてUnityへimportします。 Assets→Import Package→Custom PackageでImportします。 Swiftのバージョン指定を追加します。PostProcessor.csを改修します。 SWIFT_VERSIONで4.0を下記で指定して追加 PostProcessor.cs using UnityEngine; using UnityEditor; using UnityEditor.Callbacks; using UnityEditor.iOS.Xcode; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; namespace UnitySwift { public static class PostProcessor { [PostProcessBuild] public static void OnPostProcessBuild(BuildTarget buildTarget, string buildPath) { if(buildTarget == BuildTarget.iOS) { // So PBXProject.GetPBXProjectPath returns wrong path, we need to construct path by ourselves instead // var projPath = PBXProject.GetPBXProjectPath(buildPath); var projPath = buildPath + "/Unity-iPhone.xcodeproj/project.pbxproj"; var proj = new PBXProject(); proj.ReadFromFile(projPath); var targetGuid = proj.TargetGuidByName(PBXProject.GetUnityTargetName()); //// Configure build settings proj.SetBuildProperty(targetGuid, "ENABLE_BITCODE", "NO"); proj.SetBuildProperty(targetGuid, "SWIFT_OBJC_BRIDGING_HEADER", "Libraries/UnitySwift/UnitySwift-Bridging-Header.h"); proj.SetBuildProperty(targetGuid, "SWIFT_OBJC_INTERFACE_HEADER_NAME", "unityswift-Swift.h"); proj.AddBuildProperty(targetGuid, "LD_RUNPATH_SEARCH_PATHS", "@executable_path/Frameworks"); proj.AddBuildProperty(targetGuid, "SWIFT_VERSION", "4.0"); proj.WriteToFile(projPath); } } } } ビルドしてiOSプロジェクトを書き出す File→Build Settings→Buildで書き出されるディレクトリ名を決めて作成。 Unity-iPhone.xcodeprojをXcodeで展開します。 Xcode上での作業 Xcodeを開くと下記のようなディレクトリ構造になっています。 AlertのコードはUnity-iPhone→Libraries→Plugins→iOSに内包されてます。 Unityで追加したファイルはLibrariesに入るみたいです。 先程、ビルド周りのEditer拡張で指定した下記はこちらに設定されていますので、確認します。 ①、Swiftのバージョン指定する(今回はSwift4.0) ②、Objective-C Bridging Headerの設定 ③、Objective-C Generated Interface Header Nameの設定 Swiftコードは下記です。ここで必要なことは下記です。 ①、クラスは NSObject を継承する ②、クラスのスコープを public にする ※ public にするのは、Objective-C++から直接呼び出したいクラスおよびメソッドだけでも良い。 ③、メソッドに@objcを付ける AlertPlugin.swift public class AlertPlugin : NSObject { @objc static func showAlert() { let alertView = UIAlertController(title: "Title", message: "AlertMessage", preferredStyle: UIAlertController.Style.alert) let okAction = UIAlertAction(title: "OK", style: UIAlertAction.Style.default, handler:nil) let cancelButton = UIAlertAction(title: "Cancel", style: UIAlertAction.Style.cancel, handler:nil) alertView.addAction(okAction) alertView.addAction(cancelButton) UIApplication.shared.keyWindow?.rootViewController?.present(alertView, animated: true, completion: nil) } } Objective-C++コードです。ここでのポイントは、下記です。 ①、extern "C"宣言でCインターフェイスを作成。 ②、Objective-C Generated Interface Header Nameで設定しているunityswift-Swift.hをimportすること。 これをimportするとObjective-C++のクラスのように呼び出すことができる。 AlertPlugin.mm #import "unityswift-Swift.h" extern "C" { void _showAlert() { [AlertPlugin showAlert]; } } 実機確認 参考
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Couchbase Mobileアプリケーション開発へのロードマップ

はじめに Couchbase Mobileによるアプリケーション開発に関する記事や参考情報を、カテゴリー別に整理しています。 関連技術 基本的な使い方(ドキュメントより) Couchbase Lite Sync Gateway チュートリアル 利用可能な言語 Android Java Swift C#/Xamarin Java 内部機構解説 アドバンスド機能解説 参考情報
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

iOS長期インターンに参加してから3ヶ月経って、学んだこと

自己紹介 & はじめに 都内の情報系の大学に通う大学生です。iOS開発は今年はじめくらいから勉強していて、6月から長期インターンに参加しています。 インターン初めて3ヶ月ちょいですがこの間でもたくさんのことを学び、技術面に関わらず人間的な面でも色々気付かされたので、「長期インターンは楽しいぞ!」ということが少しでも伝えられればいいなと思います。 学んだこと、気づいたこと モチベーションは爆上がりする インターンシップは、学んだことが社会に出て価値になる環境の1つであるので、やはり嬉しいです。 独学では学ばない部分にも手が届いて楽しい! アプリ開発は - 提案 - 設計(デザイン?) - 実装 の3つに集約されると思うのですが、やはり提案と設計は独学ではあまりやってこなかったので、貴重な経験だと思いました。この3つができて初めて「0の状態から価値を生み出す」ということができるようになり、これがプロダクトづくりの醍醐味みたいなところもあるので、提案と設計あたりは今ではガツガツ関わっている部分でもありますw 3ヶ月位で一気にできるようになる 社員さんもインターン時代皆なったらしいのですが、最初の数カ月はわからないことだらけであまり貢献できず、少しきつい思いをしていたのですが、3ヶ月位でプロジェクト把握したり緊張がほぐれて提案とかリファクタリングとかの余裕も出てきて、「イイ感じ」になりました。おそらく僕に限った話ではなく、割とどこでもそうだと思います。 インターンきついなと思ったら、とりあえず3ヶ月くらいを目標に頑張ってみるのがいいかもしれません! メガネ生活楽 らくちんです 提案は楽しい やはり言われたものをただやるのは貢献感なく性に合ってなかったので、企画とか提案とかをエンジニアでもどんどんできる環境があるという軸でインターンを探して、現在のインターンとご縁がありました。 とはいうものの独学ではコーディングは経験できますが、他人への提案は経験できないので多少不安はありました。しかしそこは社員さんが「自信3割くらいでもどんどん言ってくれていい。野球で打率3割だったらすごいじゃん。」というふうに安心させてくれて、この部分は本当にインターン先に恵まれているなと思いました。 提案➣デザイン➣実装の楽しさ 「ここのUIわかりづらくね??」というちょっとした提案も真摯に受け止めてくれました。独学にはない初めての経験だったので少し勇気がいり、また既存のものを壊すのはちょっと抵抗がありましたが、全然やってくれていいよというふうに後押ししてくれたので、実装を進めることができました。自分が0から提案したものが自分でデザイン、コーディングできて、実際に世に出されて利用者さんから「使いやすい」との言葉を頂いたときは、本当に達成感がありました。この経験ができるのはあまり他のインターンでは無いのかなと思います。 この経験から、段々と提案に対する障壁がなくなってきました。 MTGありがたい! 社員さんに自分の現状や悩み、今後の行動方針とかを聞ける1on1でのMTGの時間があったのですが、普段の業務ではあまり話にならないことがたくさん聞けて、不安も解消されて、自分のマインドの良いところ、改善していけることろ、がどんどん明らかになっていき、よりクリアな感情でモチベーションも高くなったので、本当に「MTGありがたい!」って感じです! 野球の打率の話もここで聞きましたw 仕事中に参考した部分はとりあえず全部ブックマーク! おすすめです。懐かしさを感じつつ復習することができます。 デザインしたよ 自分は個人開発ではデザインカンプを作るということはあまりしなかったのですが、書き起こしたほうがより良いプロダクトが作れるということに、インターンを通して気付かされました。 「figma」というデザインツールがあるのですが、iPhoneのフレームおいて、そこにいろんなパーツおいていろんなUIのパターン出しして、そこから取捨選択していくイメージです。 大事なのは「なぜこのデザインにしたのか言語化する」、「デザインで何を解決したいか都度思い出す」、「頭で考えるより書き出す」あたりだと思いました。 自分はUI設計の問題点を指摘して新規UIのデザインカンプを作っていたのですが、この3つを意識して創出したデザインは自分も社員さんも納得できるようなものであったし、実際にリリースされても「使いやすい!」という声が聞けたときは本当に嬉しかったです。 できなさそうだな、、ということでも割とできる 個人開発のことは「できることベース」で実装していたものが、インターンでは「やりたいことベース」でした。おそらく個人開発のときは実装する自信があまりなかったからです。しかしインターンでいざ実装するとなると引き下がるわけには行かないので実装するのですが、意外とできるようなものでした。やはりできることベースよりもやりたいことベースのほうがプロダクトとして成功するだろうし、「やりたいこと」➣「実装」の逆算の経験を何度も何度も積むと、割ともう何でもいけんじゃね?という自身がつきました。 好きでやれているので、すばらしい 就職に有利だから、周りに差をつけたいから、みたいな理由で長期インターンを始める学生も多いと思います。全然悪いことではないし僕が口出しする権利はまったくないのですが、イチ個人の意見として、楽しくなかったらやる意味がないのかなと思います。 好きでやれている、という状況を作ってくれている今のインターン先には本当に感謝していますし、だからこそもっと貢献していきたいと思えます。 さいごに 何も言うこと思いつかないので、「プロダクトづくりたのしいぞ!」とだけ言っておきます!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

iOS長期インターンに参加してから4ヶ月経って、学んだこと

自己紹介 & はじめに 都内の情報系の大学に通う大学生です。iOS開発は今年はじめくらいから勉強していて、6月から長期インターンに参加しています。 インターン初めて3ヶ月ちょいですがこの間でもたくさんのことを学び、技術面に関わらず人間的な面でも色々気付かされたので、「長期インターンは楽しいぞ!」ということが少しでも伝えられればいいなと思います。 学んだこと、気づいたこと モチベーションは爆上がりする インターンシップは、学んだことが社会に出て価値になる環境の1つであるので、やはり嬉しいです。 独学では学ばない部分にも手が届いて楽しい! アプリ開発は - 提案 - 設計(デザイン?) - 実装 の3つに集約されると思うのですが、やはり提案と設計は独学ではあまりやってこなかったので、貴重な経験だと思いました。この3つができて初めて「0の状態から価値を生み出す」ということができるようになり、これがプロダクトづくりの醍醐味みたいなところもあるので、提案と設計あたりは今ではガツガツ関わっている部分でもありますw 3ヶ月位で一気にできるようになる 社員さんもインターン時代皆なったらしいのですが、最初の数カ月はわからないことだらけであまり貢献できず、少しきつい思いをしていたのですが、3ヶ月位でプロジェクト把握したり緊張がほぐれて提案とかリファクタリングとかの余裕も出てきて、「イイ感じ」になりました。おそらく僕に限った話ではなく、割とどこでもそうだと思います。 インターンきついなと思ったら、とりあえず3ヶ月くらいを目標に頑張ってみるのがいいかもしれません! メガネ生活楽 らくちんです 提案は楽しい やはり言われたものをただやるのは貢献感なく性に合ってなかったので、企画とか提案とかをエンジニアでもどんどんできる環境があるという軸でインターンを探して、現在のインターンとご縁がありました。 とはいうものの独学ではコーディングは経験できますが、他人への提案は経験できないので多少不安はありました。しかしそこは社員さんが「自信3割くらいでもどんどん言ってくれていい。野球で打率3割だったらすごいじゃん。」というふうに安心させてくれて、この部分は本当にインターン先に恵まれているなと思いました。 提案➣デザイン➣実装の楽しさ 「ここのUIわかりづらくね??」というちょっとした提案も真摯に受け止めてくれました。独学にはない初めての経験だったので少し勇気がいり、また既存のものを壊すのはちょっと抵抗がありましたが、全然やってくれていいよというふうに後押ししてくれたので、実装を進めることができました。自分が0から提案したものが自分でデザイン、コーディングできて、実際に世に出されて利用者さんから「使いやすい」との言葉を頂いたときは、本当に達成感がありました。この経験ができるのはあまり他のインターンでは無いのかなと思います。 この経験から、段々と提案に対する障壁がなくなってきました。 MTGありがたい! 社員さんに自分の現状や悩み、今後の行動方針とかを聞ける1on1でのMTGの時間があったのですが、普段の業務ではあまり話にならないことがたくさん聞けて、不安も解消されて、自分のマインドの良いところ、改善していけることろ、がどんどん明らかになっていき、よりクリアな感情でモチベーションも高くなったので、本当に「MTGありがたい!」って感じです! 野球の打率の話もここで聞きましたw 仕事中に参考した部分はとりあえず全部ブックマーク! おすすめです。懐かしさを感じつつ復習することができます。 デザインしたよ 自分は個人開発ではデザインカンプを作るということはあまりしなかったのですが、書き起こしたほうがより良いプロダクトが作れるということに、インターンを通して気付かされました。 「figma」というデザインツールがあるのですが、iPhoneのフレームおいて、そこにいろんなパーツおいていろんなUIのパターン出しして、そこから取捨選択していくイメージです。 大事なのは「なぜこのデザインにしたのか言語化する」、「デザインで何を解決したいか都度思い出す」、「頭で考えるより書き出す」あたりだと思いました。 自分はUI設計の問題点を指摘して新規UIのデザインカンプを作っていたのですが、この3つを意識して創出したデザインは自分も社員さんも納得できるようなものであったし、実際にリリースされても「使いやすい!」という声が聞けたときは本当に嬉しかったです。 できなさそうだな、、ということでも割とできる 個人開発のことは「できることベース」で実装していたものが、インターンでは「やりたいことベース」でした。おそらく個人開発のときは実装する自信があまりなかったからです。しかしインターンでいざ実装するとなると引き下がるわけには行かないので実装するのですが、意外とできるようなものでした。やはりできることベースよりもやりたいことベースのほうがプロダクトとして成功するだろうし、「やりたいこと」➣「実装」の逆算の経験を何度も何度も積むと、割ともう何でもいけんじゃね?という自身がつきました。 好きでやれているので、すばらしい 就職に有利だから、周りに差をつけたいから、みたいな理由で長期インターンを始める学生も多いと思います。全然悪いことではないし僕が口出しする権利はまったくないのですが、イチ個人のひとりごととして、楽しくなかったらやる意味がないのかなと思います。 好きでやれている、という状況を作ってくれている今のインターン先には本当に感謝していますし、だからこそもっと貢献していきたいと思えます。 さいごに 何も言うこと思いつかないので、「プロダクトづくりたのしいぞ!」とだけ言っておきます!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Swift】iTunes APIでカンタンに楽曲情報を取得する方法

iTunes APIのURLを叩くだけでカンタンに楽曲情報を取得できる方法を見つけたので、具体的なコードなども含めてご説明します。 独自構造体を作る まずは楽曲情報を格納するための自作構造体を作ります。 import Foundation struct MusicInfoModel: Codable { var trackViewUrl : String var collectionId : Int var trackId : Int var artistName: String var trackName: String var collectionName: String var artworkUrl100: String var releaseDate: String var primaryGenreName: String init(trackViewUrl: String, collectionId: Int, trackId: Int, artistName: String, trackName: String, collectionName: String, artworkUrl100: String, releaseDate: String, primaryGenreName: String) { self.trackViewUrl = trackViewUrl self.collectionId = collectionId self.trackId = trackId self.artistName = artistName self.trackName = trackName self.collectionName = collectionName self.artworkUrl100 = artworkUrl100 self.releaseDate = releaseDate self.primaryGenreName = primaryGenreName } } 取得している情報は コレクションID トラックID アーティスト名 トラック名 コレクション名 アートワーク画像 リリース日 ジャンル名 といった感じ。 iTunes APIで楽曲情報を取得 次にiTunes APIで楽曲情報を取得する関数を定義。 //曲検索関数 public func fetchTrack(text: String, completion: @escaping (([MusicInfoModel]) -> Void)) { let newStr = text.replacingOccurrences(of: " ", with: "+") var compornent = URLComponents(string: "https://itunes.apple.com/search")! compornent.queryItems = [ URLQueryItem(name: "term", value: newStr), URLQueryItem(name: "media", value: "music"), URLQueryItem(name: "country", value: "JP") ] let task = URLSession.shared.dataTask(with: compornent.url!) { (data, _, error) in if error == nil, let data = data { do { let datas = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as! NSDictionary let tracks = datas.object(forKey: "results") as! [[String: AnyObject]] if tracks.count > 0 { let trackDatas = tracks.map{ MusicInfoModel( trackViewUrl: $0["trackViewUrl"] as? String ?? "", collectionId: $0["collectionId"] as? Int ?? 0, trackId: $0["trackId"] as? Int ?? 0, artistName: $0["artistName"] as? String ?? "", trackName: $0["trackName"] as? String ?? "", collectionName: $0["collectionName"] as? String ?? "", artworkUrl100: $0["artworkUrl100"] as? String ?? "", releaseDate: $0["releaseDate"] as? String ?? "", primaryGenreName: $0["primaryGenreName"] as? String ?? "") } completion(trackDatas) } else{ print("検索結果が見つかりませんでした") } } catch let error { print("error",error) } } } task.resume() } 関数を呼び出す時は以下の通り。 self.fetchTrack(text: value, completion: { tracks in print(tracks[0]) }) 参考URL
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Swift】URLからAppleMusicを開く方法

SwiftでAppleMusicのURLを取得した後、AppleMusicアプリを開く方法に躓いたのでメモとして残しておきます。 //AppleMusicを開くための関数、urlを引数としている func openAppMusic(url: String) { DispatchQueue.main.async { guard let url: URL = URL(string: url) else { return } // URLを開く UIApplication.shared.open(url, options: [:]) { success in if success { } } } } //ボタンをタップしたらAppleMusicのURLを開く関数(例) @objc func onPressButton(_ sender : Any){ self.openAppMusic(url: "AppleMusicのURL") } メインスレッドで開くのを忘れがちなので注意が必要。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

RxSwiftのVariableは廃止。VariableからBehaviorRelayに変更する時のメモ

RxSwift4でVariableが廃止されてる。 リプレイスの時とかのメモ。 やること ・VariableをBehaviorRelayへ変更 ・BehaviorRelayの()に(value: hogeを追加 ・.valueってのをacceptへ変更 let myVariable = Variable<Bool>(true) myVariable.value = false let myBehaviorRelay = BehaviorRelay<Bool>(value: true) myBehaviorRelay.accept(false) 参考
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む