Swiftにおける基本のMVCアーキテクチャについて
デザインパターンといえば、MVC・MVP・CleanArchitectureなど様々なアーキテクチャありますが、今回は基本の基本、であるMVCについて、Swiftにおける基本をまとめました。
MVCについて説明
まずMVCとはアプリケーションを実装するためのデザインパターンで、内部データをユーザーが直接参照・編集する情報から分離します。以下の3つの部分に分割されます。 ・Model - ビジネスロジックなど処理部分を書きます ・View - 画面への表示部分を担当します ・Controller - Model、Viewへ指示を出します 下画像はMVCのイメージ図
SwfitにおけるMVC
さてSwiftでのMVCはViewとControllerが一つになっています。なのでMassiveViewControllerと言われるようなViewControllerの肥大化が課題となっています。この課題はCleanArchitectureやMVVMなど、他のデザインパターンで解決できるのですが、今回はMVCの理解を深めましょう。
Modelを作成
今回はTestViewController.swiftとTestModel.swiftを作成してVCとMの連携を簡単に実装します。下記ソースでは、TestModelにデリゲートを作成して値を監視するようにしています。
protocol TestModelDelegate:class { func did() } class TestModel{ private num:int = 0 var delegate:TestModelDelegate? = nil //値をセット public func setNum(_num:int){ num = _num delegate?.did() } }
ViewControllerを作成
ViewControllerではTestModelを作成し、変数の管理やビジネスロジックの実装を任せます。
class TestViewController :UIViewController,TestModelDelegate{ private var tModel = TestModel() override func viewDidLoad(){ super.viewDidLoad() tModel.delegate = self tModel.setNum(2) } }
以上で基本的なMVCの実装は簡単にできます。
最後に
何かと問題点も指摘されているMVCなので今後はMVPやCleanArchitectureについても挑戦したいと思います。
【ARKit】lightEstimateでカメラ画像の明るさを環境光に反映
上画像のようにARKitでカメラ画像の明るさをライティングに反映する方法をご紹介します。
①SceneKitのライティングを作成
まずはライティング用ノードを作成してrootNodeに追加します。
var sceneLight: SCNLight!//シーンのライト override func viewDidLoad() { ... sceneLight = SCNLight() sceneLight.type = .omni //豆電球のように球状に光が広がるライト let lightNode = SCNNode() lightNode.light = sceneLight lightNode.position = SCNVector3(0,0,2) self.sceneView.scene.rootNode.addChildNode(lightNode) //ライティング用のノードをARSCNViewに追加
②ARWorldTrackingConfigurationでisLightEstimationEnabledをtrueに
isLightEstimationEnabledをtrueにすることで環境光に合わせてレンダリングすることができます。
let configuration = ARWorldTrackingConfiguration() configuration.isLightEstimationEnabled = true sceneView.session.run(configuration)
③rendererでライティング情報を反映
①で作成したSceneLightにlightEstimateの光量と色を反映させます。
func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) { guard let lightEstimate = self.sceneView.session.currentFrame?.lightEstimate else { return } let ambientLightEstimate = lightEstimate.ambientIntensity let ambientColorTemperature = lightEstimate.ambientColorTemperature sceneLight!.intensity = ambientLightEstimate //光量を反映 sceneLight!.temperature = ambientColorTemperature //環境光の色 if ambientLightEstimate < 100 { print("Lighting Is Too Dark") } }
このように手軽に反映できます。素晴らしいですね。
Swfitでアプリ内にテキストファイルを書き出す
テキストファイルを書き出してiTunesで取り出す手順を紹介します。
①FileManager.default.urlsでドキュメントのパスを取得
let documentDirectoryFileURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last {
②テキストファイル名を追加
let targetTextFilePath = documentDirectoryFileURL.appendingPathComponent(テキストファイル名)
③initialText.writeで書き出し
do { try initialText.write(to: targetTextFilePath, atomically: true, encoding: String.Encoding.utf8) } catch let error as NSError { print("\(error)") }
下記の場所へ書き出されます。
/Users/Username/Library/Developer/CoreSimulator/Devices/~/data/Containers/Data/Application/~/Documents
④iTunesから取り出し
iTunesの端末設定のファイル共有にてアプリを選択し取り出すことができます。
CoreLocationで位置情報と方角を取得する
CoreLocationで位置情報を取得する方法を紹介します。
①CoreLocation.frameworkを追加
「General>Linked Frameworks and Libraries」にCoreLocation.frameworkを追加しimportします。
import CoreLocation
②info.plistにKeyを設定
info.plistでPrivacy - Location When In Use Usage Descriptionを設定します。Valueは空でも大丈夫です。
③LocationManagerを作成
ロケーションマネージャーを作成し、delegateをselfに設定します。CLLocationManagerDelegateを継承するのを忘れずに。
myLocationManager = CLLocationManager() myLocationManager.delegate = self
認証ステータスをチェックしてnotDeterminedの場合認証ウィンドウを表示させます。
let status = CLLocationManager.authorizationStatus() if(status == CLAuthorizationStatus.notDetermined){ self.myLocationManager.requestWhenInUseAuthorization() }
方角を取得する場合はstartUpdatingHeading、位置を取得する場合はstartUpdatingLocationを実行
myLocationManager.startUpdatingHeading() //方角アップデート myLocationManager.startUpdatingLocation() //位置アップデート
④方角を取得する
func locationManager(_ manager:CLLocationManager,didUpdateHeading newHeading:CLHeading){ print("方角:".appendingFormat("%.2f",newHeading.magneticHeading)) }
⑤位置を取得する
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { guard let newLocation = locations.first else { return } print("緯度:".appendingFormat("%.2f",newLocation.coordinate.latitude)) print("緯度:".appendingFormat("%.2f",newLocation.coordinate.longitude)) }
plistは忘れがちなので注意してください。
スマートフォン史上最強「A12 Bionic」とは
9月に発表されたiPhone XS/XS Max/XRには「アップル A12バイオニック(Apple A12 Bionic)」が採用されています。
世界最大の半導体製造ファウンダリ「TSMC(台湾)」で製造された7ナノメートルプロセスラインで生産される最新鋭のモバイルプロセッサです。
自分もiPhoneXSを購入して使ってみましたがX/8Plusと比べてみてもかなり快適。今回は、この新しいチップの何がすごいのかについてまとめてみました。
69億個のトランジスタ
A12Bionicは、システム構成は同じながらiPhoneX/8PlusのA11Bionicプロセッサの43億個を大きく上回る69億個のトランジスタを集積しています。高性能コア2個と高効率コア4個の組み合わせで、動作クロックの向上と合わせて高性能コアの性能が最大15パーセントも引き上げられています。
また稼働コア数と動作速度をダイナミックに切り替えるフュージョンアーキテクチャを採用することでA12Bionicプロセッサでは従来よりピーク性能を引き上げると同時に、アイドル時の消費電力を低く抑えることで高性能化とバッテリ動作時間という相反するスペックを高い次元で両立しています。
強化されたメモリとGPU
XRはiPhoneXと同じ3GBのメモリですが、XSシリーズではiPhoneとして過去最大容量の4GBに増強されています。
またGPUコアにはアップル独自設計のアーキテクチャが採用されており、A11Bionicの3コアから4コアに強化されており、A12では新たに3Dオブジェクトを構成するポリゴンをより細かく分割して滑らかなオブジェクト形状を実現する「テッセレーション」と、3Dオブジェクトの表面の質感表現を向上させる「マルチレイヤーレンダリング」がサポートされ、3Dゲームなどの映像のリアリティを向上させることができるようになりました。また限られたメモリリソースを有効に活用する「ロスレスメモリ圧縮」技術が導入され、メモリ領域や帯域の消費を抑えることが可能になっています。
ニューラルエンジンの大幅強化
A12ではA11の60000億回/秒の演算能力であるのに対し、5兆回/秒と大幅に向上。ニューラルエンジンの役割は、画像認識や音声認識と行った機械学習をより高速かつ提唱秘伝rヒョクで推論処理することにあります。これによってiPhone内部でほとんどの演算処理(エッジサイド処理)が可能となり、通信トラフィックの低減とプライバシー情報に対するセキュリティ向上を実現しています。
スマートHDR
大幅に強化されたニューラルエンジンや画像処理プロセッサによって可能となったのが「スマートHDR」です。
一度のシャッター操作で自動的に露出やタイミングの異なる複数の写真を撮影し、車道やハイライトを適切なバランスで合成しつつリアリティに溢れた一枚の写真をリアルタイムに合成します。また「ボケと深度コントロール」機能が搭載され、撮影後にも背景のぼかし具合を調整できます。
ARアプリケーションの性能が飛躍的に上昇
これら供されたGPU、画像信号プロセッサ、ニューラルエンジンの組み合わせはARアプリケーションのリアリティを飛躍的に向上させています。これらの機能はCoreMLやARKit、メタル2などのAPIを通じてデベロッパに解放されており、より魅力的なアプリケーションの開発が可能となっている。
まとめ
アップルは今回、AR/VRや画像/音声認識と行った新聞屋の処理を実行するコアプロセッサを大幅に強化することで、新しい時代のアプリケーションが求める性能を限られたバッテリ容量で実現することを目指し、A12Bionicの強化ポイントを選定したと言えるでしょう。2020年に発売されるとされる片目8KのMRデバイスが楽しみです。
分かりにくいSwiftのオプショナル型「?」と「!」の違いについて
オプショナル型について簡略に説明している記事が少なかったので短くまとめて見ました。
オプショナル型とは?
オプショナル型は変数にnilの代入を許容するデータ型です。nilはデータがない状態。 そして、オプショナル型の変数には「?」か「!」をつけます。 こんな風に
var num:Int? var text:String!
iOSではnilでアプリが落ちないように、基本的にはnilは出さないように設計されています。 ただ、このオプショナル型を使うとnilを変数に代入できるようになるということ。 非オプショナルの変数は使うことができません。 つまり以下のソースはエラーが出ます。
var test: String println(piyo) //エラーが出ます
【※注意】ちなみに変数の宣言以外で使う「?」「!」はオプショナル型ではありません。
「?」と「!」の違い
では、「?」と「!」はどうやって使い分けるのでしょうか。
一般的なオプショナル型は「?」ですが、「!」は暗黙的アンラップ型(Implicitly Unwrapped Optional)と呼ばれます。下記のソースをご覧ください。
var optional: Int? = 10 // オプショナル型 // そのまま出力するとOptional()がつく... println(optional) // => Optional(10) // !をつけると強制的にアンラップする println(optional!) // => 10
オプショナル型はそのまま出力すると変数として使えません。「!」をつけてアンラップする必要があります。
アンラップ型「!」について
アンラップ型「!」にも種類があります。暗黙的アンラップと強制的アンラップ。
変数宣言時に使う「!」は暗黙的アンラップで、変数を使うときに「!」をつける必要が無くなります。
強制的アンラップはオプショナル型を使うときに「!」をつけることによってOptional()でラップされずに使うことができます。
まとめ
初心者の方は色々考えると複雑になるので、nilを防ぐために「?」でオプショナル型宣言し「!」でアンラップとだけおぼえましょう。 今回紹介したのは基本的な使い方ですが、応用編はまた別の記事にしたいと思います。
フリーランスとしてのカスタマーサクセスとは
友人に進められて読んだビジネス本『カスタマーサクセス――サブスクリプション時代に求められる「顧客の成功」10の原則』が、今の自分の働き方と重なる部分があり面白かったので紹介します。
カスタマーサクセスとフリーランスの仕事
カスタマーサクセス(顧客満足)はサブスクリプションモデルによって顧客のリテンション率(顧客維持率)を保つために、これからのビジネスにはなくてはならない考え方だそうです。本書を読んで感じたのは、フリーランスとして働くということはサブスクリプションモデルに近いということ。エンジニアとして常に顧客満足を意識しながら受託契約を更新してもらうことは大切ですよね。気が引き締まります。
カスタマーサクセスとは?
カスタマーサクセス(CS)とは顧客満足のことです。近頃よく耳にするCX(顧客経験)とCO(顧客成果)の足し算によって生まれるこのCSが、現在のSaaSの成功を実現する上で欠かせない指標であると言います。顧客の購買動機には行動ロイヤルティ(利便性)と心理ロイヤルティ(好み)があって、CSでより大切なのは心理ロイヤルティの方だそうです。商品や会社を好きになってもらうことが先決なのだそう。
カスタマーサクセス10の原則
本書では10の原則によってカスタマーサクセスという指標をより具体化しています。一つ一つの言葉が刺さります。
1. 正しい顧客に販売する
2.顧客とベンダーは何もしなければ離れる
3.顧客が期待しているのは大成功だ
4.絶えずカスタマーヘルスを把握・管理する
5.ロイヤルティの構築にもう個人間の関係はいらない
6.本当に拡張可能な差別化要因は商品だけ
7.タイムトゥバリューの向上にとことん取り組む
8.顧客の指標を深く理解する
9.ハードデータの指標でカスタマーサクセスを進める
10.トップダウンかつ、全社レベルで取り組む
いくらサービスが安かろうが、いくら実現不可能なプロジェクトであろうが、顧客が求めているのは大成功なのですね。顧客にとっての大成功とは何なのか常に管理しながら仕事をすること。
まとめ
本書では、カスタマーサクセスはサブスクリプションモデルのSaaSだけにとどまらず、今後あらゆるサービスに応用されていくと言います。フリーランスだけではなくて、働くということは常に誰かのサクセスを実現することなのかもしれません。