20210829のSwiftに関する記事は9件です。

【Swift】オプショナル型とアンラップ

Swiftのオプショナル型とアンラップが個人的に便利だなと思ったのでまとめたいと思います。 オプショナル型 そもそもオプショナル型とはなんぞやということですが、 簡単に言うと「nilを許容するデータの型」のことです。 以下のように変数の宣言時にデータ型の後ろに「?」をつけることでその変数をオプショナル型に出来ます。 var num: Int? ちなみに普通に宣言した場合のものは非オプショナル型と言われたりもします。 オプショナル型の何が便利なのかというと「nilによるエラーを回避できる」ところです。 以下のようにコードを書くと通常ではエラーになってしまいますが、オプショナル型ではそれを回避できます。 もし仮に変数にnilが入ってしまった場合でもプログラムが止まることはなく処理を続行してくれます。 そのため、nilのせいで意図せずプログラムが終了してしまうことを防ぐことができます。 var num: Int? print(num) アンラップ 実は、オプショナル型の変数はそのままでは使用することができません。 以下のコードを実行すると… ``` var num: Int? num = 1 print(num) ``` このような結果になってしまいます。 Optional(1) そのため、オプショナル型をプログラムで使う場合には処理をしてあげる必要があります。 その処理のことを「アンラップ」といいます。 アンラップの方法は大きく分けて2種類あります。 if let 〜 / guard let 〜 一つ目の方法は、以下のように「if / guard」の条件の部分でletによる変数宣言を行い成功時には処理を続行する方法です var num: Int? num = 1 if let unwrapnum = num { print(unwrapnum) } 結果は以下のようになります。 1 強制アンラップ もう一つの方法は、以下のように変数に「!」をつけることでnilチェックを行わずにアンラップする方法です。 var num: Int? num = 1 print(num!) 結果は以下のようになります。 1 ただし、nilの場合に強制アンラップを行うとエラーになってしまうため、 強制アンラップは値がnilでないことが確信できる場合のみにしか使ってはいけません。 まとめ 既に他の方も同じような記事を書いてはいましたが、自分が今回学んだこととしてアウトプットさせていただきました。 そのため、他の記事と内容が被っている点などは目を瞑っていただけるとありがたいです。 参考文献 SwiftUI対応 たった2日でマスターできるiPhoneアプリ開発集中講座 Xcode 12/iOS 14 OptionalをUnwrapする3つの方法
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

今日作成したUI記録(layerとAutoLayout)

今回の内容 コード Main.storyboardで表示するパーツを作成しておきます. @IBOutlet weak var topWhiteView: UIView! @IBOutlet weak var beforeResultLabel: UILabel! @IBOutlet weak var beforeResultDateLabel: UILabel! @IBOutlet weak var beforeResultLocationLabel: UILabel! @IBOutlet weak var showSignUpViewButton: UIButton! Layer UILabelは3つとも同じ.cornerRadiusの値を設定してるので、UILabelを持つ配列を引数にしています。 static func topViewDesign(targetLabels:[UILabel],targetView:UIView,targetButton:UIButton){ targetLabels.forEach({$0.layer.cornerRadius = 13.0; $0.layer.masksToBounds = true}) targetView.layer.cornerRadius = 25.0 targetView.layer.shadowOffset = CGSize(width: 10, height: 10) targetView.layer.shadowOpacity = 0.65 targetView.layer.shadowRadius = 5 targetButton.layer.cornerRadius = 20.0 targetButton.layer.shadowOffset = CGSize(width: 10, height: 10) targetButton.layer.shadowOpacity = 0.65 targetButton.layer.shadowRadius = 5 } tabBar tabBar.barTintColor = .systemGreen tabBar.tintColor = .white tabBar.unselectedItemTintColor = .systemIndigo tabBar.layer.cornerRadius = 25.0 tabBar.layer.masksToBounds = true tabBar.layer.maskedCorners = [.layerMaxXMinYCorner,.layerMinXMinYCorner] AutoLayout 終わり ご指摘、ご質問などありましたら、コメントまでお願い致します。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

enum Associated Values と Raw Values を両立させる

背景 Swift の enum においては、 Associated Values と Raw Values を利用することができます。 これらはそれぞれ単独での利用は問題ないのですが、両方を同時に利用するとすると、コンパイルエラーとなってしまいます。 それぞれ単独での利用は OK Associated Values enum Screen { case home(tabIndex: Int) case search case setting } Raw Values enum Screen: String { case home = "Home" case search = "Search" case setting = "Setting" } 同時利用が NG Associated Values & Raw Values enum Screen: String { case home(tabIndex: Int) // コンパイルエラー "Enum with raw type cannot have cases with arguments" case search case setting } コンパイルエラーを回避して、 Associated Values と Raw Values を両立させようというのが今回の内容です。 ユースケースとしては、次のように iOS アプリの画面を enum で表現することを想定します。 ホーム/検索/設定の3画面をタブ( UITabbar を利用した下タブ)で構成 ホーム画面は可変個のタブストリップ(上タブ)で子画面を保持 Associated Values を利用 スクリーンビュー測定のため、 enum 毎に特定の文字列を定義 Raw Valuesを利用 どうするのか Associated Values はそのまま。 Raw Values を protocol RawRepresentable に適合させることで実現します。 For any enumeration with a string, integer, or floating-point raw type, the Swift compiler automatically adds RawRepresentable conformance. When defining your own custom enumeration, you give it a raw type by specifying the raw type as the first item in the enumeration’s type inheritance list. You can also use literals to specify values for one or more cases. とあるように、 Raw Values 自体は Swift コンパイラが protocol RawRepresentable に自動的に適合してくれた結果なので、これを自分で実装することとなります。 具体的には、以下のイニシャライザとプロパティ実装が要求されます。 ( associatedtype RawValue については、型推論が効くため省略可能です) init?(rawValue: Self.RawValue) var rawValue: Self.RawValue 上述の想定ユースケースにおける enum Screen を例にした実装だと、次の通りです。 enum Screen: RawRepresentable { case home(tabIndex: Int) case search case setting init?(rawValue: String) { switch rawValue { case Screen.search.rawValue: self = .search case Screen.setting.rawValue: self = .setting default: if let regex = try? NSRegularExpression(pattern: "^Home_Tab(.+)$"), let match = regex.firstMatch(in: rawValue, range: NSRange(location: 0, length: rawValue.count)), let range = Range(match.range(at: 1), in: rawValue), let tabIndex = Int(rawValue[range]) { // `case home(tabIndex: Int)` の rawValue フォーマットに合致 self = .home(tabIndex: tabIndex) } else { return nil } } } var rawValue: String { switch self { case .home(let tabIndex): return "Home_Tab\(tabIndex)" case .search: return "Search" case .setting: return "Setting" } } } メリット・デメリット メリットとしては、 Associated Values と Raw Values を両立可能という結果そのものがあります。 もう少し具体的な例だと、 Raw Values 実装に依存した既存コードが大量にあるプロジェクトにおいて、 enum に Associated Values を利用した case を追加する必要性が発生した場合に、影響を最小限に抑えることが可能となってきます。 デメリットとしては、 init?(rawValue: Self.RawValue)の実装が煩雑になる enum の表現力 / 記述容易性が失われる といったことが挙げられます。 特に後者において、通常の enum 実装では、列挙子と rawValue の一意性を少ない記述で簡潔に表現でき、コンパイラの静的解析による保証もついてくる enum Screen: String { case home = "Home" case search = "Search" case setting = "Search" // コンパイルエラー "Raw value for enum case is not unique" } のですが、自分で protocol RawRepresentable への適合を実装するとなると、このあたりの恩恵が失われてしまいます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

MVCからVIPERに変えて得られたこと

本記事について 本記事では、VIPERアーキテクチャについて学習し、MVCからVIPERに変えて得られたことについてご紹介します。 VIPERアーキテクチャとは? VIPERとは、単一責務原則に基づき、Cleanでモジュール化された構造を実現するアーキテクチャ 「VIPER」は、View、Interactor、Presenter、Entity、Router の頭文字を取った造語 雑なMVCからVIPERアーキテクチャに変えてみた 過去にMVC開発したアプリをVIPERアーキテクチャに変えて、得られる恩恵について紹介します。 全体像 今回はリスト表示の箇所をVIPERに変えます。 クラス図は以下の通りです。 View 役割 Presenterから指示された画面の更新 Presenterへのイベントの通知 CharaListViewController.swift import UIKit protocol CharaListViewInterface: AnyObject { func displayCharaList(_ chara: [CharaEntity]) func displayLodingAlert() func displayFinishLodingAlert() func alertListError(error: Error) } final class CharaListViewController: UIViewController { @IBOutlet weak var charaCollectionView: UICollectionView! { didSet { charaCollectionView.dataSource = self charaCollectionView.delegate = self charaCollectionView.registerNib(cellType: CharaCollectionViewCell.self) charaCollectionView.backgroundColor = Asset.viewBgColor.color } } @IBOutlet weak var postCharaButton: UIButton! { didSet { postCharaButton.allMaskCorner() postCharaButton.addTarget(self, action: #selector(movePost), for: .touchUpInside) } } // プロトコルを介してPresenterへアクセス var presenter: CharaListPresenterInterface! private var chara: [CharaEntity] = [] override func viewDidLoad() { super.viewDidLoad() presenter.viewDidLoad() } } // MARK: - private method private extension CharaListViewController { @objc private func movePost() { presenter.didTapCharaPost() } } // MARK: - Interface extension CharaListViewController: CharaListViewInterface { func displayCharaList(_ chara: [CharaEntity]) { self.chara = chara self.searchResultChara = chara DispatchQueue.main.async { self.charaCollectionView.reloadData() } } func displayLodingAlert() { self.startLoad() } func displayFinishLodingAlert() { self.doneMessage() } func alertListError(error: Error) { self.alertError(error: error) } } // MARK: - UICollection Delegate extension CharaListViewController: UICollectionViewDataSource { func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return self.searchResultChara.count } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(for: indexPath) as CharaCollectionViewCell let component = CharaCollectionViewCell.Component(charaInfo: self.searchResultChara[indexPath.row]) cell.setupCell(component: component) return cell } } extension CharaListViewController: UICollectionViewDelegate { func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { self.presenter.didSelectChara(selectedChara: self.searchResultChara[indexPath.row]) } } Presenter 役割 各要素間の橋渡し役 CharaListPresenter.swift import Foundation protocol CharaListPresenterInterface: AnyObject { func viewDidLoad() func didSelectChara(selectedChara: CharaEntity) func didTapCharaPost() } final class CharaListPresenter { private let view: CharaListViewInterface private let interactor: CharaListInteractorInterface private let router: CharaListRouterInterface init( view: CharaListViewInterface, interactor: CharaListInteractorInterface, router: CharaListRouter ) { self.view = view self.interactor = interactor self.router = router } } extension CharaListPresenter: CharaListPresenterInterface { func viewDidLoad() { self.view.displayLodingAlert() self.interactor.fetchCharaList { result in self.view.displayFinishLodingAlert() switch result { case let .success(characters): self.view.displayCharaList(characters) case let .failure(error): self.view.alertListError(error: error) } } } func didSelectChara(selectedChara: CharaEntity) { interactor.saveSpotlightChara(selectedChara: selectedChara) interactor.saveUserDefaultsChara(selectedChara: selectedChara) router.pushCharaDetail(chara: selectedChara) } func didTapCharaPost() { router.presentCharaPost() } } Interactor 役割 データ操作とユースケースの定義 CharaListInteractor.swift import Foundation protocol CharaListInteractorInterface: AnyObject { func fetchCharaList(_ completion: @escaping ((Result<[CharaEntity], Error>) -> Void)) func saveSpotlightChara(selectedChara: CharaEntity) func saveUserDefaultsChara(selectedChara: CharaEntity) } final class CharaListInteractor: CharaListInteractorInterface { private let firebaseRepository: FirebaseRepositoryProtocol private let spotlight: SpotlightRepositoryProtocol init(firebaseRepository: FirebaseRepositoryProtocol, spotlight: SpotlightRepositoryProtocol) { self.firebaseRepository = firebaseRepository self.spotlight = spotlight } func fetchCharaList(_ completion: @escaping ((Result<[CharaEntity], Error>) -> Void)) { firebaseRepository.fetchChara { completion($0) } } func saveSpotlightChara(selectedChara: CharaEntity) { spotlight.saveChara(charaInfo: selectedChara) } func saveUserDefaultsChara(selectedChara: CharaEntity) { UserDefaultsClient().saveChara( selectedChara, forkey: "chara://detail?id=\(selectedChara.id)" ) } } Entity 役割 各要素間でやり取りされるデータ CharaEntity.swift import Foundation struct CharaEntity: Codable { var id: Int var name: String var description: String var imageRef: String var isFavorite: Bool = false var order: Date } Router 役割 画面遷移とDI Presenterから画面遷移の依頼を受け取る CharaListRouter.swift import UIKit protocol CharaListRouterInterface: AnyObject { func pushCharaDetail(chara: CharaEntity) func presentCharaPost() } final class CharaListRouter { private let viewController: CharaListViewController init(viewController: CharaListViewController) { self.viewController = viewController } static func assembleModule() -> CharaListViewController { let storyboard = UIStoryboard(name: "CharaList", bundle: nil) let viewController = storyboard.instantiateViewController(withIdentifier: "list") as! CharaListViewController let interactor = CharaListInteractor(firebaseRepository: FirebaseRepository(), spotlight: SpotlightRepository()) let router = CharaListRouter(viewController: viewController) let presenter = CharaListPresenter( view: viewController, interactor: interactor, router: router ) viewController.presenter = presenter return viewController } } extension CharaListRouter: CharaListRouterInterface { func pushCharaDetail(chara: CharaEntity) { let storyboard = UIStoryboard(name: "CharaDetail", bundle: nil) let nextView = storyboard.instantiateViewController(withIdentifier: "detail") as! CharaDetailViewController viewController.navigationController?.pushViewController(nextView, animated: true) } func presentCharaPost() { let storyboard = UIStoryboard(name: "CharaPost", bundle: nil) let nextView = storyboard.instantiateViewController(withIdentifier: "post") as! CharaPostViewController viewController.present(nextView, animated: true) } } 得られたメリット 単一責務 MVCやMVVMとは違い、必然と凝集度の高いメソッドの定義ができると感じました。 例えば、タップ時の処理について MVCだと色々処理が混ざってしまいます。当然メソッドの切り分けはできますが、規模が大きくなると、ViewControllerが肥大化するため、見通しは悪くなると思います。 CharaListViewController(MVC).swift func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { spotlight.saveChara(charaInfo: model.entity[indexPath.row]) UserDefaultsClient().saveChara( model.entity[indexPath.row], forkey: "chara://detail?id=\(model.entity[indexPath.row].id)" ) let storyboard: UIStoryboard = UIStoryboard(name: "CharaDetail", bundle: nil) let nextView = storyboard.instantiateViewController(withIdentifier: "detail") as! CharaDetailViewController nextView.charaDetail = model.entity[indexPath.row] if let tmp = UserDefaultsClient().loadChara(key: "favo=\(model.entity[indexPath.row].id)") { nextView.charaDetail.isFavorite = tmp.isFavorite } self.navigationController?.pushViewController(nextView, animated: true) } しかし、VIPERに切り替えることで、かなり見通しが良くなり、「どの処理が何をしているのか」が明確になります。 CharaListPresenter.swift func didSelectChara(selectedChara: CharaEntity) { interactor.saveSpotlightChara(selectedChara: selectedChara) interactor.saveUserDefaultsChara(selectedChara: selectedChara) router.pushCharaDetail(chara: selectedChara) } 最後に 今回はVIPERを学びましたが、別のアーキテクチャも学び比較していければと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Swift CodableでネストしたJSONを変換する

はじめに HotPepperBeautyAPIから返ってきたJSONをDecodeしようとした際に少し詰まったので備忘録として書きます。 やりたいこと 下記のJSONをDecodeし、accessのデータを使用したい。 { "results": { "api_version": "1.26", "results_available": 27716, "results_returned": "10", "results_start": 1, "shop": [ { "access": "渋谷駅ハチ公口徒歩3分バスケットボールストリート(渋谷センター街)通りの1階 ウエンディーズ白馬ビル4階", "address": "東京都渋谷区宇田川町26-11 白馬ビル4階", "band": "不可", "barrier_free": "なし :心地よい時間をご提供できるよう随時サポートさせて頂きます。", "budget": { "average": "通常平均:3280円/宴会平均:3280円/ランチ平均:3280円", "code": "B002", "name": "2001~3000円" }, ... 現状 accessを使用したく、以下の構造体を用意。 struct Shop: Codable { let access: String enum CodingKeys: String, CodingKey { case access = "access" } } エラー内容 「キーに関連付けられた値がありません」とのエラー。タイポミス等を疑い諸々チェックしたのですが、解決せず。 keyNotFound(CodingKeys(stringValue: "access", intValue: nil), Swift.DecodingError.Context(codingPath: [], debugDescription: "No value associated with key CodingKeys(stringValue: \"access\", intValue: nil) (\"access\").", underlyingError: nil)) 原因・解決方法 構造体をresultsから用意していなかったことが原因だった。なので、以下のようにresultsから構造体を作成すると無事にDecodeすることができた。 struct Results: Codable { let results: ResultsData } struct ResultsData: Codable { let shop: [Shop] } struct Shop: Codable { let access: String enum CodingKeys: String, CodingKey { case access = "access" } } 最後に ネストしたJSONは一見難しいように見えましたが、見た目通りに構造体を用意してあげることで簡単にデコードすることができました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

iOSアーキテクチャ勉強

MVC(Cocoa MVC) View 表示、入出力 Controller 入力に基づくModelとViewの制御 Model データの保持、通信 ViewControllerがViewとControllerの役割を両方持つため肥大化しがち Massive View Controllerとか呼ばれる 普通言われるMVCとはModelがデータの変更をViewに通知すると言う点で違う MVP MVCと違い入力を受け付けるのがControllerではなくViewになるViewControllerはViewとして扱われる - Supervising Controller - データバインディングによりViewがModelを監視し、データ更新があれば表示も更新する - データを加工せずに表示できるのでPresenterの負担を軽減できるがModelがViewのレイアウトに依存する - Passive View - 必ずmodelとViewの間はPresenterが介すのでViewとModelが分離するがPresenterの負担増 MVVM ViewとViewModelをデータバインディング。MVPと違うのはMVPはデリゲートやインターフェイスで処理を移譲・更新処理を行うのに対して、MVVMではデータバインディングでViewとViewModelを紐づける クリーンアーキテクチャ GUIアーキテクチャ MVC,MVP,MVVMなどUIに関するロジック クリーンアーキテクチャはUIに関するロジック(プレゼンテーション層)とシステムに関するロジック(ドメイン)を分離するのが目的 3階層システム プレゼンテーション層(ユーザーインターフェース層)html,swift, ページの表示、ページ間の遷移、ユーザーが入力した内容をビジネスロジック層に受け渡す処理などを行う、 ビジネスロジック層(アプリケーション層)php,python,ruby プレゼンテーション層、データアクセス層がすること以外が全部ここ。 データアクセス層 sql CRUDのしょりをおこなう よくMVCとかMVVMとかは全部プレゼンテーション層の話 参考 :https://qiita.com/os1ma/items/7a229585ebdd8b7d86c2 https://www.ibm.com/jp-ja/cloud/learn/three-tier-architecture https://qiita.com/navitime_tech/items/602d3286f23952ae0149#mvp-model-view-presenter
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

SwiftUIのボタンで少し凝ったハイライト表現をするには?

ButtonStyleによるハイライト表現 SwiftUI においてボタンのタップ中のハイライト表現をしたい場合、ButtonStyle を作り、configuration.isPressed によってハイライト時の見た目に変更します。以下の例ですと、タップ中はボタンの背景色が変わるようになっています。 struct CustomButtonStyle: ButtonStyle { func makeBody(configuration: Configuration) -> some View { configuration.label .padding() .foregroundColor(Color.white) // タップ中かどうかで背景色を変更する .background(configuration.isPressed ? Color.red : Color.blue) .cornerRadius(4) } } Button(action: {}, label: { Text("Button") }) // 作ったボタンスタイルを適用する .buttonStyle(CustomButtonStyle()) 少し凝ったハイライト表現をするには? しかし、タップ中かどうかによってボタンの見た目を大胆に変えたい場合、上記のような ButtonStyle による方法だと限界があります。そこで、次のような感じでタップ中かどうかによってボタンの label を簡単に変更できるボタンコンポーネントを作ってみました。 HighlightableButton( action: { // Nothing to do. }, label: { configuration in CharacterView(character: .wolverine, isPressed: configuration.isPressed) }) isPressed の値によって View の中身を自由自在に変更できるので、こんな凝ったハイライト表示も実現できてしまいます。MARVEL API を使って SwiftUI の勉強中だったので、こんなこともしてみたくなってしまいました。 今回作った HighlightableButton は次のように内部で ButtonStyle を使いつつ、label については外部から設定できるようにしています。NavigationLink 版もありますよ。 import SwiftUI struct HighlightableButton<Label>: View where Label: View { private let action: () -> Void private let label: (ButtonStyleConfiguration) -> Label init(action: @escaping () -> Void, @ViewBuilder label: @escaping (ButtonStyleConfiguration) -> Label) { self.label = label self.action = action } var body: some View { Button(action: action, label: {}) .buttonStyle(HighlightableButtonStyle { config in label(config) }) } } struct HighlightableNavigationLink<Label, Destination>: View where Label: View, Destination: View { private let destination: () -> Destination private let label: (ButtonStyleConfiguration) -> Label init(destination: @escaping () -> Destination, @ViewBuilder label: @escaping (ButtonStyleConfiguration) -> Label) { self.destination = destination self.label = label } var body: some View { NavigationLink(destination: destination, label: {}) .buttonStyle(HighlightableButtonStyle { config in label(config) }) } } private struct HighlightableButtonStyle<Label>: ButtonStyle where Label: View { private var label: (ButtonStyleConfiguration) -> Label init(@ViewBuilder label: @escaping (ButtonStyleConfiguration) -> Label) { self.label = label } func makeBody(configuration: Configuration) -> some View { label(configuration) } }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【iOS】Metal Best Practicesの解説(7) 画面スケール

Metal Best Practicesは、iOS/MacOS/tvOSのAPIであるMetalを用いた設計のベストプラクティスガイドです。 本稿では、何回かに分けてこのガイドを読み解き、コード上での実験を交えて解説していきます。 読んでそのまま理解できそうなところは飛ばしますので、原文を読みながら原文のガイドとしてご利用下さい。 また、iOSの記事なので他のOS(MacOS, tvOS)についての記載は割愛します。 他の記事の一覧は、初回記事よりご覧下さい。 Native Screen Scale (iOS and tvOS) (画面スケール) ベストプラクティス: ターゲットディスプレイの正確なピクセルサイズでドローアブルをレンダリングします。 不要なレンダリングや、テクスチャーサンプリングによるパフォーマンス低下を避けるために、ドローアブルのピクセルサイズはデバイスの物理的なピクセルサイズと同じにしましょう、という話です。 前提として、iOSにおいては、画面の描画のサイズは基本的にポイント単位で指定しますが、Metalではピクセル単位で指定するということがあります。 そのため、ドローアブルのピクセルサイズを計算するためには、UIScreenのプロパティから、ネイティブの画面サイズをnativeBoundsから、スケールファクター(1ポイントが何ピクセルに対応するか)をnativeScaleから取得する必要があります。 なお、MTKViewを用いた場合、ドロアーブルのサイズはビューのサイズと常に一致することが保証されるので、このあたりの計算を自分でする必要はありません。 結論 ドローアブルの領域が広ければ、レンダリングに時間がかかることは自明なので、まぁそうだろうなというところです。自明なことなので、今回は、サンプルコードを作って試していません。 軽く手元で試してみた限りでは、同じ1000x1000の画像を1000x1000のドローアブルに描画するのと、2000x2000のドローアブルに描画する(余った領域は空白になる)のでは、やはり1000x1000の方が高速に描画していました。 最後に iOSを使った3D処理やAR、ML、音声処理などの作品やサンプル、技術情報を発信しています。 作品ができたらTwitterで発信していきますのでフォローをお願いします? Twitterは作品や記事のリンクを貼っています。 https://twitter.com/jugemjugemjugem Qiitaは、iOS開発、とくにARや機械学習、グラフィックス処理、音声処理について発信しています。 https://qiita.com/TokyoYoshida Noteでは、連載記事を書いています。 https://note.com/tokyoyoshida Zennは機械学習が多めです。 https://zenn.dev/tokyoyoshida
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

イニシャライザとは? -init()

イニシャライザとは、 型(クラス、構造)のインスタンスを初期化(僕のイメージでは再設定)するメソッドのこと class User { let name: String // funcが不要(initキーワードのみ) init(name: String) { // 全てのプロパティを初期化する前にインスタンスメソッドを実行することはできない // printName() → コンパイルエラー self.name = name printName() // OK } // インスタンスメソッド func printName() { print(name) } } let user1 = User.init(name: "hoge") // 呼び出し時のメソッド名が省略可能 let user2 = User(name: "hoge") イニシャライザの順序 イニジャライザは、プロパティの初期化をしてからインスタンスメソッド(インスタンスプロパティにアクセス、変更するためのインスタンスの目的に関連した機能としてサポートするメソッド)を実行するという順序が存在します。 参考文献 ・https://qiita.com/shtnkgm/items/8b7979fc84a3cc065238
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む