2018年7月1日日曜日

最新ドラマ情報を管理するアプリをリリースしました!

皆様、今期のドラマ楽しんでましたでしょうか?
私は今期は何も見ていなかったのですよね…

飯豊まりえさんが出ているのを知っていれば花のち晴れ見たかった…
あと、○○な人の末路とやれたかも委員会がタイトルがすごい気になる(笑)
まぁ今更なのですが…で、友達とドラマの話をしようと思っても忘れちゃうんですよね…

あと、次期ドラマチェックするのって面倒ですよね。まとめサイト探してとか後から更新されたりとか、いつの間にか始まってて見逃したりとか…

自分が楽したいがためにそんな要望に答えるアプリを作りました!
ドラマチェッカー

iOSのみなのですが、ドラマをお気に入り登録して管理したり、放送地域設定にも対応しています。
また、公式サイトにもリンクを用意し、twitterでのみんなの反応をチェックすることも出来ます!
専用のtwitterアカウント@drm_chkもあります!

無料なのでぜひともダウンロードくださいm(_ _)m
いや、本当にお願い致します…(切実)

最新アニメ情報を管理するアプリをリリースしました!

皆様、春アニメ楽しんでましたでしょうか?
私は結構、春アニメは見ていたものが多いです。


  • 安定のルパン三世
  • 3D彼女
  • きららな仕事、こみっくがーるず
  • ペルソナ5 Everyday young life JUNES.
  • 現実はいつも稀有なものなのです!レイトン先生
  • SNSポリス
  • なんかよく分からないカリギュラ
  • おそまなゴールデンカムイ
  • 鈴羽大好きシュタインズ・ゲート
  • ヲタクに恋は難しい(真理)
  • 桐生一馬な妖怪ウォッチ


そんな時、友達と話そうと思っても忘れちゃうんですよね…

あと、次期アニメチェックするのって面倒ですよね。まとめサイト探してとか後から更新されたりとか、いつの間にか始まってて見逃したりとか…

自分が楽したいがためにそんな要望に答えるアプリを作りました!
アニメチェッカー

iOSのみなのですが、アニメをお気に入り登録して管理したり、放送地域設定にも対応しています。
また、公式サイトにもリンクを用意し、twitterでのみんなの反応をチェックすることも出来ます!
専用のtwitterアカウント@anm_chkもあります!

無料なのでぜひともダウンロードくださいm(_ _)m
いや、本当にお願い致します…(切実)

2018年6月30日土曜日

ソーシャルゲームの運営とその闇

noteにてソーシャルゲームの運営とその闇について書きました😀
私のnoteはこちら

私がソーシャルゲームを運営していた時に思っていたこと、その後に他社のソーシャルゲーム運営に携わって感じたことを書いています。
ソーシャルゲームの運営とその闇 #1
ソーシャルゲームの運営とその闇 #2
ソーシャルゲームの運営とその闇 #3
ソーシャルゲームの運営とその闇 #4
ソーシャルゲームの運営とその闇 #5
ソーシャルゲームの運営とその闇 #6
ソーシャルゲームの運営とその闇 #7
ソーシャルゲームの運営とその闇 #8
ソーシャルゲームの運営とその闇 #9

現時点では全9回ですね。今後も書き足したいことが出来たら書くと思います。
ぜひご一読頂けたら幸いです😀

2018年5月5日土曜日

ALISの購入方法

ALISはまだ国内の取引所では買えません。
購入するには海外の取引所に登録する必要があります。私は英語もそこまで出来ませんし、仮想通貨界隈も初心者です😔
そんな私でも問題なく購入出来ておりますので、興味があれば購入にチャレンジしてみましょう!
国内の取引所で扱い始めたら高騰間違いありません😀

ALISが実際に購入出来る取引所はCryptopiaです!

ただ登録の前にCryptopiaは海外の取引所なので日本円で取引は出来ません😔
なのでまずはビットコイン(BTC)を購入する必要があります!

流れとしては…
  • 国内の取引所に登録
  • 国内の取引所に日本円を送金
  • 国内の取引所にてビットコイン(BTC)を購入
  • 海外の取引所に登録
  • 国内の取引所から海外の取引所にビットコイン(BTC)を送金
  • 海外の取引所にてビットコイン(BTC)でALISを購入
という流れになります😀

国内の取引所を紹介します!

私が実際に使っている取引所から紹介したいと思います😀
私でも取引出来ているので、どの取引所も使いやすいかと!
今後、仮想通貨界隈でフットワーク軽くやり取り出来るように、全ての取引所を登録しておくことをオススメします👍

成海璃子さんのCMでも有名なbitFlyerです!
bitFlyer ビットコインを始めるなら安心・安全な取引所で

Zaif
こちらは剛力彩芽さんがCMしています。Zaifです!

coincheck
2018年頭にnem流出したcoincheckです😔
ただ、マネックスグループの子会社化、業務改善命令なども入りましたし、今後も頑張って欲しいです!むしろ逆に最もセキュリティ面はしっかりしてくるのでは!?などと思ったりしてます。
ビットコイン取引高日本一の仮想通貨取引所 coincheck bitcoin

これら取引所は本人確認や二段階認証の設定などに時間が取られますので、早めに登録しておくことをオススメします👍

さぁ海外の取引所に登録しよう!

登録するのは先程も紹介したCryptopiaです!
英語が苦手だとしても割と出て来る単語は同じようなものばかりです(DepositとかWithdrawとか)
なのですぐ読み取れるようになります😀
今後も仮想通貨界隈の情報を見ていくなら、必須の英語力(といっても最低限ですが)になりますので、まだまだ先行者利益のある今の内に読み取れるようになっておきましょう!

2018年5月4日金曜日

ALISクローズドβに参加

国産の仮想通貨であるALIS
SNSの世界では求心力のある人間の発信する情報が真となりやすい傾向があります。○○さんが紹介している商品なんだから良いものに違いないとか、正しい情報である、みたいなことですね。
本来の商品の良し悪しや情報の真偽を度外視して、発信者への信頼や忠誠が惑わせているのです😇
いわゆるステルスマーケティングですね😇

ALISはこれに対してユーザの本当の意味でのいいね👍を実現しようとしています。
価値ある記事に対してALISを報酬としたプラットフォームの構築です。

で、本題になるのですが、このプラットフォームのクローズドβに応募し、参加致しました。
今回はその所感について記事に致します(当然β版のお話です)

UIはひたすらシンプル

私の好みです😀
TOPページは以下のような感じ。
人気記事と新着記事でリスト分けされてます。
FacebookもInstagramも意外とUI複雑ですよね。設定関連とか…
記事に対してはハートボタンが用意されていたり、支払われたALISが表示されています。

記事作成もひたすらシンプル

使用感についてはnoteに似ています。
タイトルと本文に分かれており、本文はブロック単位で入力可能です。
ブロック内の改行はなく、次ブロックに入力が移る感じです。
また、ブロックにはテキストだけではなく、画像を追加したり、罫線を入力可能です。

画像でも判断出来るかと思いますが、下書きとして残しておいたり、過去に公開した記事を修正することも可能です。

β版なので運用開始次第、色々機能が追加されていくと思うのですが、これくらいシンプルな方が個人的には好きです。
結局こういったサービスの本質ってユーザの記事がメインになるので、プラットフォームとしての機能って本当最低限で良いと思うんですよね。むしろ複雑化すると億劫になっていく。
まぁ欲しいと思う記事を探しやすくする工夫は必要ですが😀

個人的にはプラットフォームの使い勝手とかはどうでもよくて、プロダクトの方向性と日本人運営という点で信頼しているので運営の方々には健康に気を付けて、頑張って欲しいですね!

次回は実際にALISを購入する方法を紹介したいと思います!

2018年5月3日木曜日

Solidityのエラー判定

CryptoZombiesにてSolidityを学びました。JavaScriptベースなので学習しやすいです。今回は関数に用いる修飾子について備忘録です。
CryptoZombies

require( 条件 )

条件がtrue(真)の時のみ処理続行。失敗時にガスの残りを返却してくれる。

assert( 条件 )

requireと似ているが、こちらはガスの返却が行われない。続行不可のエラーである場合に使用する。

assertに引っかかるような条件は事前に除外すべきだが、どうしても続行不可の場合もある。慎重に設計・検討する必要がある。

2018年5月2日水曜日

Solidityの関数修飾子

CryptoZombiesにてSolidityを学びました。JavaScriptベースなので学習しやすいです。今回は関数に用いる修飾子について備忘録です。
CryptoZombies

view

内部で状態変数を変更しない、つまりガスを消費しない

pure

view修飾子の制限に加え、状態変数の読込みも行わない

payable

イーサリアムのやり取りを行うための修飾子

2018年4月8日日曜日

音楽再生アプリを作ってみた

音楽を再生するためだけのシンプルなアプリを作ってみました。
Swift勉強がてらなのでクソ設計ですが、誰かの参考になればと思い、GitHubにて公開しております。
MITライセンスです。
[GitHub] Nokokinoko/nusic

質問などあればお気軽にどうぞ!

2018年4月5日木曜日

シリーズ完結

noteにて一つのシリーズを完結しました!

エンジニアよ、稼ぐか搾取されるか #3
エンジニアよ、稼ぐか搾取されるか #4

フリーランスとして働くために必要なスキルや、そもそも働くとは何なのか、エンジニアとして成功するために必要な能力について自分の見解ではありますが、連々と書き綴っております。
noteの方も見てもらえたら大変嬉しいです!

2018年4月4日水曜日

モーダル範囲外のタッチを判定

タッチした際にモーダル等の矩形の範囲内外を判定する方法です。
  • Xcode 8.3.3
  • Swift 3.1
import UIKit

class ExampleViewController: UIViewController {
  private var _Dismiss: Bool = false
  private let TAG: Int = 100

  override func viewDidLoad() {
    super.viewDidLoad()

    self.view.backgroundColor = UIColor.gray
    _Dismiss = false

    let viewAdd = UIView(frame: CGRect(x: 0, y: 0, width: 300, height: 400))
    viewAdd.backgroundColor = UIColor.white
    viewAdd.center = self.view.center
    viewAdd.tag = TAG
    self.view.addSubview(viewAdd)
  }

  override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
  }

  override func touchesBegan(_ touches: Set<uitouch>, with event: UIEvent?) {
    if _Dismiss {
      return
    }

    let point = touches.first?.location(in: self.view)
    let viewAdd: UIView = self.view.viewWithTag(TAG)! as UIView

    if !viewAdd.frame.contains(point!) {
      _Dismiss = true
      // 範囲外をタッチした時の処理
    }
  }
}

touchesBeganなので指が画面に触れた時のイベントです。
touchesEndedにすれば指が画面から離れた時のイベントになります。
ただ、touchesBeganに画面制御を記述すると反応の早い、ユーザビリティの高いアプリとユーザに判断されます。まぁこれも使い所次第ですが😅
課金とかにtouchesBeganで処理されたら私は速攻アプリアンインストールします😅
なんか信用出来ないですからね…

というかUIがボタンならBeganでselectな制御(グレースケールしたりとか縮小させたりとか)して、Movedで範囲内外を判定、Endedで範囲内(というかBeganで触ったものと同一のままならとか)ならselectedな制御して範囲外なら何もしない(タッチ状態フラグを解除程度)みたいな制御が普通ですね。

こういう制御例ってあまりネットに載らないですよね😇
各社ノウハウとして溜まってるだけで。
まぁ気が向いたらその辺も公開していきます🙌掲載するコード量がとんでもないことになりそう😇

2018年4月3日火曜日

遷移時にブラーを自然に重ねて表示

ブラー効果を簡単に利用するではSwiftの利用方法を紹介しました。
ただこれを使って重ねて表示(Over Current Context)するとフェードインした後、急にブラーの背景に変わって違和感があります。
今回はブラー効果を重ねて表示する際に自然に表示出来るよう調整する方法です。
  • Xcode 8.3.3
  • Swift 3.1
import UIKit

class ExampleViewController: UIViewController {
  private var _Blur: UIVisualEffectView!

  override func viewDidLoad() {
    super.viewDidLoad()

    _Blur = UIVisualEffectView(effect: UIBlurEffect(style: UIBlurEffectStyle.dark))
    _Blur.frame = self.view.frame
    _Blur.alpha = 0.0
    self.view.addSubview(_Blur)
  }

  override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
  }

  override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    UIView.animate(
      withDuration: 0.25,
      animations: { self._Blur.alpha = 1.0 }
    )
  }
}

なんか無理矢理感が否めないです🙇
ブラーをいじったり、アニメーションスタイルをいじれば良いのですが、私はそこまでのめり込むつもりがないのです😇

2018年4月2日月曜日

ブラー効果を簡単に利用する

iOSにて開発時に用意されているブラー効果(いわゆるすりガラスのようなぼかし効果です)をSwiftで簡単に利用する方法です。
  • Xcode 8.3.3
  • Swift 3.1
では早速コードになります。
let _Blur = UIVisualEffectView(effect: UIBlurEffect(style: UIBlurEffectStyle.dark))
_Blur.frame = self.view.frame
self.view.addSubview(_Blur)

この例ではUIBlurEffectStyle.darkを指定しているため黒のブラーです。
他にも.lightで白ブラー、.extraLightでlightよりも薄い白のブラーとなります。

ぼかし具合とか変えたい場合は結構いじる必要がありそうです😇
なんか実際に奥側に当たる箇所にブラー効果を加えてるのではなく、内部でスクリーンショット撮ってブラー効果を加えたものを設置してるのかな?
深く理解していませんが、そこまでApple様に加担するつもりはありませんので黙って用意されたもので我慢しておきます😇

2018年4月1日日曜日

TabBar + Navigation構成でViewに遷移

TabBarにNavigationではタブ要素にナビを追加して親子関係を作りました。
TabBarからViewに遷移ではタブのアイテムにViewへ遷移するための処理を追加しました。
今回はタブ要素にナビを追加した上で表示されたViewから別Viewへ遷移するための処理を紹介します。
  • Xcode 8.3.3
  • Swift 3.1
別Viewへ遷移するためのトリガーはボタンタッチとかでも良いですし、TableViewのCellタッチでも何でも良いです。
適切な所に処理を記述して下さい。
TabBarからViewに遷移と同様、重ねて表示(Over Current Context)します。
let vcNext = UIViewController()
vcNext.modalPresentationStyle = .overCurrentContext
parent?.parent?.present(vcNext, animated: false, completion: nil)

構成としてTabBarがアイテム要素を管理、各アイテムはNavigationであり、表示するViewControllerを持っています。
別Viewへ遷移するためのトリガーはこのViewControllerとなりますので、2つ上のparentにpresentを実行します。

なんかもう少しスマートなやり方がありそうな気がします…
相対的な指定が汎用性だったり拡張性を失わせておる😈

2018年3月31日土曜日

TabBarからViewに遷移

前回TabBarにNavigationという記事を書きました。
  • Xcode 8.3.3
  • Swift 3.1
今回はこれに加えてタブのアイテムにタブ表示に依存しないViewを追加したいと思います。
モーダルも以下コードで再現出来るので参考にして頂ければと。
import UIKit

class TabViewController: UITabBarController, UITabBarControllerDelegate {
 
 class DummyViewController: UIViewController {}

 private var _Example1: UINavigationController!
 private var _Example2: UINavigationController!
 private var _Example3: UINavigationController!
 private var _Modal: DummyViewController!
 
 override func viewDidLoad() {
  super.viewDidLoad()
  
  self.view.backgroundColor = UIColor.white
  
  _Example1 = UINavigationController(rootViewController: Example1ViewController())
  _Example2 = UINavigationController(rootViewController: Example2ViewController())
  _Example3 = UINavigationController(rootViewController: Example3ViewController())
  _Modal = DummyViewController()
  
  _Example1.tabBarItem = UITabBarItem(tabBarSystemItem: UITabBarSystemItem.featured, tag: 1)
  _Example2.tabBarItem = UITabBarItem(tabBarSystemItem: UITabBarSystemItem.featured, tag: 2)
  _Example3.tabBarItem = UITabBarItem(tabBarSystemItem: UITabBarSystemItem.featured, tag: 3)
  _Modal.tabBarItem = UITabBarItem(tabBarSystemItem: UITabBarSystemItem.featured, tag: 4)
  
  self.setViewControllers([_Example1!, _Example2!, _Example3!, _Modal!], animated: false)
  self.delegate = self
 }
 
 override func didReceiveMemoryWarning() {
  super.didReceiveMemoryWarning()
 }

 func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
  if viewController is DummyViewController {
   let example = ExampleViewController()
   example.modalPresentationStyle = .overCurrentContext
   self.present(example, animated: false, completion: nil)
   return false
  }
  return true
 }
}

これで_Modalに該当するアイテムをタップした時だけタブ内ではなく、ExampleViewControllerを重ねて表示します。

ExampleViewControllerの背景を黒透過にして白いレイヤを表示するよう制御すれば、モーダルを再現出来るかと🙆

2018年3月30日金曜日

TabBarにNavigation

以前StoryBoardを使わずにUITabBarControllerStoryBoardを使わずにUINavigationControllerという記事を書きました。
  • Xcode 8.3.3
  • Swift 3.1
今回はUITabBarControllerにNavigationを追加したいと思います。
もちろんStoryBoardは使いません。
全然関係ないですが、これを実現しようとGoogle先生に聞くとStoryBoardやらSegueやらばかりがHITします😇
あれって使ってる人いるんですね😇

親View

import UIKit

class TabViewController: UITabBarController {
 
 private var _Example1: UINavigationController!
 private var _Example2: UINavigationController!
 private var _Example3: UINavigationController!
 
 override func viewDidLoad() {
  super.viewDidLoad()
  
  self.view.backgroundColor = UIColor.white
  
  _Example1 = UINavigationController(rootViewController: Example1ViewController())
  _Example2 = UINavigationController(rootViewController: Example2ViewController())
  _Example3 = UINavigationController(rootViewController: Example3ViewController())
  
  _Example1.tabBarItem = UITabBarItem(tabBarSystemItem: UITabBarSystemItem.featured, tag: 1)
  _Example2.tabBarItem = UITabBarItem(tabBarSystemItem: UITabBarSystemItem.featured, tag: 2)
  _Example3.tabBarItem = UITabBarItem(tabBarSystemItem: UITabBarSystemItem.featured, tag: 3)
  
  self.setViewControllers([_Example1!, _Example2!, _Example3!], animated: false)
 }
 
 override func didReceiveMemoryWarning() {
  super.didReceiveMemoryWarning()
 }
}


子となるView

import UIKit

class Example1ViewController: UIViewController {
 override func viewDidLoad() {
  super.viewDidLoad()
  
  self.navigationItem.title = "Example1"
  
  self.navigationItem.leftBarButtonItem = nil
  
  let btnRight = UIBarButtonItem(title: "Next >", style: UIBarButtonItemStyle.plain, target: self, action: #selector(Example1ViewController.goNext))
  self.navigationItem.rightBarButtonItem = btnRight
 }
 
 override func didReceiveMemoryWarning() {
  super.didReceiveMemoryWarning()
 }
 
 @objc func goNext() {
  self.navigationController?.pushViewController(Example1NextViewController(), animated: true)
 }
}


子ViewからNavigationで遷移するView

StoryBoardを使わずにUINavigationControllerという記事ではExample2ViewControllerでした(紛らわしくてすいません🙇)
import UIKit

class Example1NextViewController: UIViewController {
 override func viewDidLoad() {
  super.viewDidLoad()
  
  self.navigationItem.title = "Example1Next"
  
  let btnLeft = UIBarButtonItem(title: "< Back", style: UIBarButtonItemStyle.plain, target: self, action: #selector(Example1NextViewController.goBack))
  self.navigationItem.leftBarButtonItem = btnLeft
  
  self.navigationItem.rightBarButtonItem = nil
 }
 
 override func didReceiveMemoryWarning() {
  super.didReceiveMemoryWarning()
 }
 
 @objc func goBack() {
  self.navigationController?.popViewController(animated: true)
 }
}


Example2, 3についても同じように実装すればタブで切替えながらナビからも操作出来るようになります!
自分のコードから抽出して掲載しているので動かない等あればお気軽にどうぞ!

2018年3月29日木曜日

セクション設定したTableView

以前Xibを利用してTableViewを実装する方法を紹介しました。
Xibを使ってTableViewのCellを登録・その1
Xibを使ってTableViewのCellを登録・その2
  • Xcode 8.3.3
  • Swift 3.1
今回はこのテーブルにセクションを設定したいと思います。
コードは同じのを使い回します🙇
元コードを再掲。行数3のテーブルを表示するだけのViewControllerです😀
import UIKit

class ParentViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
  override func viewDidLoad() {
    super.viewDidLoad()

    _TableView = UITableView()
    _TableView?.frame = self.view.frame
    _TableView?.register(UINib(nibName: "ExampleTableViewCell", bundle: nil), forCellReuseIdentifier: "ExampleIdentifier")
    _TableView?.delegate = self
    _TableView?.dataSource = self
    self.view.addSubview(_TableView)
  }

  override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
  }

  // データ数
  func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return 3
  }

  // セルデータを返す
  func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    var cell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "ExampleIdentifier", for: indexPath)
    switch indexPath.row {
      case 1:
        cell.textLabel?.text = "1行目"
      case 2:
        cell.textLabel?.text = "2行目"
      case 3:
        cell.textLabel?.text = "3行目"
      default: break
    }
    return cell
  }

  // セル選択
  func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    // セル選択時の処理
  }
}


ではここにセクションを2つ追加してみます。
一応分かりやすいようにセクション1は行数3、セクション2は行数4として設定します。
セクション設定とセクション毎のデータ設定を把握してもらえればと😀
import UIKit

class ParentViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
  override func viewDidLoad() {
    super.viewDidLoad()

    _TableView = UITableView()
    _TableView?.frame = self.view.frame
    _TableView?.register(UINib(nibName: "ExampleTableViewCell", bundle: nil), forCellReuseIdentifier: "ExampleIdentifier")
    _TableView?.delegate = self
    _TableView?.dataSource = self
    self.view.addSubview(_TableView)
  }

  override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
  }

  // セクション数
  func numberOfSections(in tableView: UITableView) -> Int {
    return 2
  }

  // セクション名
  func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    if section == 1 {
      return "セクション1だよ"
    }
    else if section == 2 {
      return "セクション2になります!"
    }
    return nil
  }

  // セクション単位のデータ数
  func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    if section == 1 {
      return 3
    }
    else if section == 2 {
      return 4
    }
    return 0
  }

  // セルデータを返す
  func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    var cell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "ExampleIdentifier", for: indexPath)

    if indexPath.section == 1 {
      switch indexPath.row {
        case 1:
          cell.textLabel?.text = "セクション1の1行目"
        case 2:
          cell.textLabel?.text = "セクション1の2行目"
        case 3:
          cell.textLabel?.text = "セクション1の3行目"
        default: break
      }
    }
    else if indexPath.section == 2 {
      switch indexPath.row {
        case 1:
          cell.textLabel?.text = "セクション2の1行目"
        case 2:
          cell.textLabel?.text = "セクション2の2行目"
        case 3:
          cell.textLabel?.text = "セクション2の3行目"
        case 4:
          cell.textLabel?.text = "セクション2の4行目"
        default: break
      }
    }

    return cell
  }

  // セル選択
  func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    // セル選択時の処理
  }
}


通常こんなハードコーディングすることはありません。
JSON等を解析して配列にしたりして利用することとなると思います。
データ数を返すメソッドをcount使ったりすると思うので、適宜改善して頂ければと!

2018年3月28日水曜日

StoryBoardを使わずにUINavigationController

以前ブログにも書きましたがStoryBoardを使わずに開発をしており、今回はUINavigationControllerを実装していきます。
  • Xcode 8.3.3
  • Swift 3.1
これもUITableViewController同様、難しいことはないです。
ある程度Xcode側で用意されてるので、それを利用するだけなので😅
ただし細かい調整したい場合は元クラスを調べる等、調査が必要ですので適宜Jump to definitionしましょう🙆

動作としてExample1のナビの右上NextをタップするとExample2へ遷移。
Example2ではナビの左上BackをタップでExample1へ戻れるようにします。
import UIKit

class Example1ViewController: UIViewController {
 override func viewDidLoad() {
  super.viewDidLoad()
  
  self.navigationItem.title = "Example1"
  
  self.navigationItem.leftBarButtonItem = nil
  
  let btnRight = UIBarButtonItem(title: "Next >", style: UIBarButtonItemStyle.plain, target: self, action: #selector(Example1ViewController.goNext))
  self.navigationItem.rightBarButtonItem = btnRight
 }
 
 override func didReceiveMemoryWarning() {
  super.didReceiveMemoryWarning()
 }
 
 @objc func goNext() {
  self.navigationController?.pushViewController(Example2ViewController(), animated: true)
 }
}</textarea><br />
<br />
<textarea class="code">import UIKit

class Example2ViewController: UIViewController {
 override func viewDidLoad() {
  super.viewDidLoad()
  
  self.navigationItem.title = "Example2"
  
  let btnLeft = UIBarButtonItem(title: "< Back", style: UIBarButtonItemStyle.plain, target: self, action: #selector(Example2ViewController.goBack))
  self.navigationItem.leftBarButtonItem = btnLeft
  
  self.navigationItem.rightBarButtonItem = nil
 }
 
 override func didReceiveMemoryWarning() {
  super.didReceiveMemoryWarning()
 }
 
 @objc func goBack() {
  self.navigationController?.popViewController(animated: true)
 }
}

使わないleftBarButtonItemやrightBarButtonItemをnilしなくても設定しなければ何も表示されませんが、今後の事も考えると初期化(あえて非表示してますよアピール)しておきましょう。
また、通常こんなハードコーディングをすることはありません。
例としてあえてnil設定を記述したのは、条件によってnilしたりアイテム設定したりというのが書きやすいようにです😀
abstractみたい(Swiftではprotocol extensionか?)にして他メソッドで設定するのも良いですし🙌

最後にこのViewControllerを呼出しましょう。
let example1 = UINavigationController(rootViewController: Example1ViewController())
self.present(example1, animated: true, completion: nil)

我、アクセス権を要求す

SwiftにてMediaPlayer関連の処理を実装している際、以下のようなエラーが👊
[access] This app has crashed because it attempted to access privacy-sensitive data without a usage description. 
The app's Info.plist must contain an NSAppleMusicUsageDescription key with a string value explaining to the user how the app uses this data.

毎回載せてるので一応環境も。
  • Xcode 8.3.3
  • Swift 3.1
まぁ意味は読んだままなんですが、ユーザのプライバシー情報見ようとしてるな?使用目的をInfo.plistに書けよな!とのこと🙇
天下のApple様、敵いませんわ。

ということでInfo.plistを開いて+ボタンを押して追加しましょう。
キー名にPrivacy - XXXというのがあるのでコードに応じて使用目的をValueに書きましょう。これがそのままアプリが該当の情報を見ようとした時にアラートとして表示されます。
調べた情報を見ると、Valueが空文字でも起動可、XcodeのValidateも可、らしいですが、アプリ申請時にリジェクトされるそうです。
なのでやましい理由があるわけでもないので、素直に書いておきましょう。

また、このアラートの文言を多言語対応したい場合、Info.plistにはデフォルト言語にて記述。
他の言語についてはおなじみのInfoPlist.stringsにて多言語対応しましょう!
InfoPlist.stringsについては一応この記事を参考に。
[iOS] アプリ名を国ごと変更したい場合

Baseにはデフォルト言語を記述し、Japanaseには日本語にて記述します。
ここはシステム的な文言になるので、ふざけない方が良い気がします(例えば最高の時間を提供しますとかクールなサウンドを楽しみますとか…書いてて寒いですが😅)
[ Base ]
"NSAppleMusicUsageDescription" = "Play Music";

[ Japanese ]
"NSAppleMusicUsageDescription" = "音楽を再生します";

最後にInfo.plist上のキー名と内部のキー名、簡単な説明の一覧を下記しておきます!ご参考までに🙌
  • Privacy - Bluetooth Peripheral Usage Description
    • NSBluetoothPeripheralUsageDescription
    • Blootooth
  • Privacy - Calendars Usage Description
    • NSCalendarsUsageDescription
    • カレンダー
  • Privacy - Camera Usage Description
    • NSCameraUsageDescription
    • カメラ
  • Privacy - Contacts Usage Description
    • NSContactsUsageDescription
    • 連絡先
  • Privacy - Health Share Usage Description
    • NSHealthShareUsageDescription
    • ヘルス
  • Privacy - Health Update Usage Description
    • NSHealthUpdateUsageDescription
    • ヘルスの更新
  • Privacy - HomeKit Usage Description
    • NSHomeKitUsageDescription
    • ホームキット
  • Privacy - Location Always Usage Description
    • NSLocationAlwaysUsageDescription
    • 位置情報 (常に許可)
  • Privacy - Location When In Use Usage Description
    • NSLocationWhenInUseUsageDescription
    • 位置情報 (使用中のみ許可)
  • Privacy - Microphone Usage Description
    • NSMicrophoneUsageDescription
    • マイク
  • Privacy - Motion Usage Description
    • NSMotionUsageDescription
    • 加速度センサ
  • Privacy - Music Usage Description
    • NSAppleMusicUsageDescription
    • ミュージック
  • Privacy - Photo Library Usage Description
    • NSPhotoLibraryUsageDescription
    • 写真ライブラリ
  • Privacy - Reminders Usage Description
    • NSRemindersUsageDescription
    • リマインダー
  • Privacy - Siri Usage Description
    • NSSiriUsageDescription
    • Siri
  • Privacy - Speech Recognition Usage Description
    • NSSpeechRecognitionUsageDescription
    • 音声認識

2018年3月27日火曜日

StoryBoardを使わずにUITabBarController

以前ブログにも書きましたがStoryBoardを使わずに開発をしており、今回はUITabBarControllerを実装していきます。
  • Xcode 8.3.3
  • Swift 3.1
タブに3つのアイテムを持ったTabBarControllerを作ります。
まぁそこまで難しいコードでもないです。Google先生に聞けばすぐ出てきます😅
import UIKit

class TabViewController: UITabBarController {
 
 private var _Example1: UIViewController!
 private var _Example2: UIViewController!
 private var _Example3: UIViewController!
 
 override func viewDidLoad() {
  super.viewDidLoad()
  
  self.view.backgroundColor = UIColor.white
  
  _Example1 = UIViewController()
  _Example2 = UIViewController()
  _Example3 = UIViewController()
  
  _Example1.tabBarItem = UITabBarItem(tabBarSystemItem: UITabBarSystemItem.featured, tag: 1)
  _Example2.tabBarItem = UITabBarItem(tabBarSystemItem: UITabBarSystemItem.featured, tag: 2)
  _Example3.tabBarItem = UITabBarItem(tabBarSystemItem: UITabBarSystemItem.featured, tag: 3)
  
  self.setViewControllers([_Example1!, _Example2!, _Example3!], animated: false)
 }
 
 override func didReceiveMemoryWarning() {
  super.didReceiveMemoryWarning()
 }
}

タブのアイテム画像は全部featuredですが、実行すればTabBarControllerが確認出来ると思います!

2018年3月26日月曜日

だから嫌いなんだ

Swiftで開発中に以下のようなエラーに見舞われました。
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[UIViewController _loadViewFromNibNamed:bundle:] loaded the XXX nib but the view outlet was not set.'
  • Xcode 8.3.3
  • Swift 3.1
ファイル構成とやりたいことは下記。
PlayViewController.swift
PlayView.swift
PlayView.xib

PlayViewController内でPlayViewを生成する。
PlayViewはUIViewを継承していて、xibファイルを元にレイアウト。
これでPlayViewを使用する前に一度実行してみたら、先のエラーが発生しました😇

意味が分からなすぎて発狂するところでしたが、救いの手が🙏
ViewControllerが自動で読むxibファイルに注意

  • XXXViewControllerクラスはXXXViewController.xibを読み込もうとする
  • 読み込めなければ、Controllerを除いたファイルを読み込もうとする(XXXView.xib)
先のような構成だとPlayViewControllerはPlayViewController.xibを読み込もうとするが、用意していないので、次にPlayView.xibを読み込もうとする。
PlayView.xibはたしかにあるのだが、PlayViewで使用されることを想定しているのでエラー。こういうことでした😇
これってXcode側で制御出来ないのかな…まぁApple様の高尚な考えがあるのでしょう。

サイト様の例にもありますが、PlayContentViewなどにリネームするのが良さそうですね🙆