音楽を再生するためだけのシンプルなアプリを作ってみました。
Swift勉強がてらなのでクソ設計ですが、誰かの参考になればと思い、GitHubにて公開しております。
MITライセンスです。
[GitHub] Nokokinoko/nusic
質問などあればお気軽にどうぞ!
2018年4月8日日曜日
2018年4月4日水曜日
モーダル範囲外のタッチを判定
タッチした際にモーダル等の矩形の範囲内外を判定する方法です。
touchesBeganなので指が画面に触れた時のイベントです。
touchesEndedにすれば指が画面から離れた時のイベントになります。
ただ、touchesBeganに画面制御を記述すると反応の早い、ユーザビリティの高いアプリとユーザに判断されます。まぁこれも使い所次第ですが😅
課金とかにtouchesBeganで処理されたら私は速攻アプリアンインストールします😅
なんか信用出来ないですからね…
というかUIがボタンならBeganでselectな制御(グレースケールしたりとか縮小させたりとか)して、Movedで範囲内外を判定、Endedで範囲内(というかBeganで触ったものと同一のままならとか)ならselectedな制御して範囲外なら何もしない(タッチ状態フラグを解除程度)みたいな制御が普通ですね。
こういう制御例ってあまりネットに載らないですよね😇
各社ノウハウとして溜まってるだけで。
まぁ気が向いたらその辺も公開していきます🙌掲載するコード量がとんでもないことになりそう😇
- 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)するとフェードインした後、急にブラーの背景に変わって違和感があります。
今回はブラー効果を重ねて表示する際に自然に表示出来るよう調整する方法です。
なんか無理矢理感が否めないです🙇
ブラーをいじったり、アニメーションスタイルをいじれば良いのですが、私はそこまでのめり込むつもりがないのです😇
ただこれを使って重ねて表示(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で簡単に利用する方法です。
この例ではUIBlurEffectStyle.darkを指定しているため黒のブラーです。
他にも.lightで白ブラー、.extraLightでlightよりも薄い白のブラーとなります。
ぼかし具合とか変えたい場合は結構いじる必要がありそうです😇
なんか実際に奥側に当たる箇所にブラー効果を加えてるのではなく、内部でスクリーンショット撮ってブラー効果を加えたものを設置してるのかな?
深く理解していませんが、そこまでApple様に加担するつもりはありませんので黙って用意されたもので我慢しておきます😇
- 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へ遷移するための処理を紹介します。
適切な所に処理を記述して下さい。
TabBarからViewに遷移と同様、重ねて表示(Over Current Context)します。
構成としてTabBarがアイテム要素を管理、各アイテムはNavigationであり、表示するViewControllerを持っています。
別Viewへ遷移するためのトリガーはこのViewControllerとなりますので、2つ上のparentにpresentを実行します。
なんかもう少しスマートなやり方がありそうな気がします…
相対的な指定が汎用性だったり拡張性を失わせておる😈
TabBarからViewに遷移ではタブのアイテムにViewへ遷移するための処理を追加しました。
今回はタブ要素にナビを追加した上で表示されたViewから別Viewへ遷移するための処理を紹介します。
- Xcode 8.3.3
- Swift 3.1
適切な所に処理を記述して下さい。
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という記事を書きました。
モーダルも以下コードで再現出来るので参考にして頂ければと。
これで_Modalに該当するアイテムをタップした時だけタブ内ではなく、ExampleViewControllerを重ねて表示します。
ExampleViewControllerの背景を黒透過にして白いレイヤを表示するよう制御すれば、モーダルを再現出来るかと🙆
- Xcode 8.3.3
- Swift 3.1
モーダルも以下コードで再現出来るので参考にして頂ければと。
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を使わずにUITabBarControllerとStoryBoardを使わずにUINavigationControllerという記事を書きました。
もちろんStoryBoardは使いません。
全然関係ないですが、これを実現しようとGoogle先生に聞くとStoryBoardやらSegueやらばかりがHITします😇
あれって使ってる人いるんですね😇
Example2, 3についても同じように実装すればタブで切替えながらナビからも操作出来るようになります!
自分のコードから抽出して掲載しているので動かない等あればお気軽にどうぞ!
- Xcode 8.3.3
- Swift 3.1
もちろん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
コードは同じのを使い回します🙇
元コードを再掲。行数3のテーブルを表示するだけのViewControllerです😀
ではここにセクションを2つ追加してみます。
一応分かりやすいようにセクション1は行数3、セクション2は行数4として設定します。
セクション設定とセクション毎のデータ設定を把握してもらえればと😀
通常こんなハードコーディングすることはありません。
JSON等を解析して配列にしたりして利用することとなると思います。
データ数を返すメソッドをcount使ったりすると思うので、適宜改善して頂ければと!
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側で用意されてるので、それを利用するだけなので😅
ただし細かい調整したい場合は元クラスを調べる等、調査が必要ですので適宜Jump to definitionしましょう🙆
動作としてExample1のナビの右上NextをタップするとExample2へ遷移。
Example2ではナビの左上BackをタップでExample1へ戻れるようにします。
使わないleftBarButtonItemやrightBarButtonItemをnilしなくても設定しなければ何も表示されませんが、今後の事も考えると初期化(あえて非表示してますよアピール)しておきましょう。
また、通常こんなハードコーディングをすることはありません。
例としてあえてnil設定を記述したのは、条件によってnilしたりアイテム設定したりというのが書きやすいようにです😀
abstractみたい(Swiftではprotocol extensionか?)にして他メソッドで設定するのも良いですし🙌
最後にこのViewControllerを呼出しましょう。
- Xcode 8.3.3
- Swift 3.1
ある程度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.
毎回載せてるので一応環境も。
また、このアラートの文言を多言語対応したい場合、Info.plistにはデフォルト言語にて記述。
他の言語についてはおなじみのInfoPlist.stringsにて多言語対応しましょう!
InfoPlist.stringsについては一応この記事を参考に。
[iOS] アプリ名を国ごと変更したい場合
Baseにはデフォルト言語を記述し、Japanaseには日本語にて記述します。
ここはシステム的な文言になるので、ふざけない方が良い気がします(例えば最高の時間を提供しますとかクールなサウンドを楽しみますとか…書いてて寒いですが😅)
最後にInfo.plist上のキー名と内部のキー名、簡単な説明の一覧を下記しておきます!ご参考までに🙌
[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を実装していきます。
まぁそこまで難しいコードでもないです。Google先生に聞けばすぐ出てきます😅
タブのアイテム画像は全部featuredですが、実行すればTabBarControllerが確認出来ると思います!
- Xcode 8.3.3
- Swift 3.1
まぁそこまで難しいコードでもないです。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.'
PlayViewController.swift
PlayView.swift
PlayView.xib
PlayViewController内でPlayViewを生成する。
PlayViewはUIViewを継承していて、xibファイルを元にレイアウト。
これでPlayViewを使用する前に一度実行してみたら、先のエラーが発生しました😇
意味が分からなすぎて発狂するところでしたが、救いの手が🙏
ViewControllerが自動で読むxibファイルに注意
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などにリネームするのが良さそうですね🙆
Xibを使ってTableViewのCellを登録・その2
前回の記事でxibファイルの作成を説明しました。
今回は実際にコードから登録&呼出しについて。
本来セクション等も合わせて説明したいですが、とりあえず今回は3行のテーブルを表示する処理に限定します。
UITableViewDelegateとUITableViewDataSourceを継承し、コード内のメソッドを実装してください(実装しないとエラーになります)
9行目の処理にてTableViewにregisterメソッドにて登録しています
nibNameには前回作成したファイル名を指定します。
後から指定するためのforCellReuseIdentifierも一緒に登録しており、こちらは定数で定義するかメソッドから取得するようにしましょう(今回は簡素にするため直接指定しています)
その辺のプログラマとしての常識はいちいち書くのも面倒なので適宜読み替えて下さい。
26行目の処理にて登録してあるCellを呼出しています。
指定したIDをwithIdentifierに渡してください。
これでxibファイルのレイアウトで3行のTableViewが生成されるはずです!
簡単ではありますが以上になります。質問などあればお気軽にどうぞ!
今回は実際にコードから登録&呼出しについて。
- Xcode 8.3.3
- Swift 3.1
せっかくならdelegate
TableViewを持つ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) {
// セル選択時の処理
}
}
本来セクション等も合わせて説明したいですが、とりあえず今回は3行のテーブルを表示する処理に限定します。
UITableViewDelegateとUITableViewDataSourceを継承し、コード内のメソッドを実装してください(実装しないとエラーになります)
9行目の処理にてTableViewにregisterメソッドにて登録しています
nibNameには前回作成したファイル名を指定します。
後から指定するためのforCellReuseIdentifierも一緒に登録しており、こちらは定数で定義するかメソッドから取得するようにしましょう(今回は簡素にするため直接指定しています)
その辺のプログラマとしての常識はいちいち書くのも面倒なので適宜読み替えて下さい。
26行目の処理にて登録してあるCellを呼出しています。
指定したIDをwithIdentifierに渡してください。
これでxibファイルのレイアウトで3行のTableViewが生成されるはずです!
簡単ではありますが以上になります。質問などあればお気軽にどうぞ!
2018年3月25日日曜日
Xibを使ってTableViewのCellを登録・その1
前回の記事でStoryBoardを使わずにアプリ開発をする方法を書きました。
しかしStoryBoardを使うメリットの一つとしてUIを直感的に設置出来るという点があります。
今回はTableViewのCellをXibでデザインして、それをコードから呼出して設定する方法を紹介します。
今回はひとまずxibファイルを作る所まで!
コード内ではNibという名称で出てきます。
これはNextstep Interface Builderの略です。Nextstepの時点でお気付きだと思いますが、Apple様のいつものやつです。
こちらはバイナリファイルとなっており、XibもビルドするとNibに変換されるとかなんとか…
StoryBoardも結局Xibの集合体とも呼べると思います。
まぁその辺は私も深く理解はしていません。というかコードを実行する上では必要のない知識なのでUIを作る上で.xibというファイルを作って、コード上ではNibという名前で指定すれば動作する程度の認識で良いかと。
ゲーム開発フレームワーク作りたいとかpsdファイルから画面設計したいとかなら必須知識ですけどね😇
そんな修羅の道歩みたくないです😇
Also create XIB fileにチェック
SubclassにUITableViewCellを指定
(名前は適当にExampleTableViewCellとしておきます)
するとExampleTableViewCell.swift, ExampleTableViewCell.xibが出来ると思います。
swiftファイルを確認すると確かにUITableViewCellを継承していることを確認出来るかと思います。
swiftファイルは今回はいじることはないのでそっ閉じでOKです🙆
xibファイルをクリックするとStoryBoardで見たような直感的(笑)の画面になるかと思います。
まず問題ないと思いますがCustom ClassがExampleTableViewCellになっていることを確認して下さい。
であとは好きにデザインして下さい。StyleやSelectionの項目をいじるなり、Labelを追加するなり😀
次の記事でコードからXibを利用する方法について書きます。
記事書くのも疲れる🙇
しかしStoryBoardを使うメリットの一つとしてUIを直感的に設置出来るという点があります。
今回はTableViewのCellをXibでデザインして、それをコードから呼出して設定する方法を紹介します。
今回はひとまずxibファイルを作る所まで!
- Xcode 8.3.3
- Swift 3.1
てかXibって何?
その前にXibとはXML Interface Builderの略らしいです。コード内ではNibという名称で出てきます。
これはNextstep Interface Builderの略です。Nextstepの時点でお気付きだと思いますが、Apple様のいつものやつです。
こちらはバイナリファイルとなっており、XibもビルドするとNibに変換されるとかなんとか…
StoryBoardも結局Xibの集合体とも呼べると思います。
まぁその辺は私も深く理解はしていません。というかコードを実行する上では必要のない知識なのでUIを作る上で.xibというファイルを作って、コード上ではNibという名前で指定すれば動作する程度の認識で良いかと。
ゲーム開発フレームワーク作りたいとかpsdファイルから画面設計したいとかなら必須知識ですけどね😇
そんな修羅の道歩みたくないです😇
まずはXibファイルを作成
XcodeにてNew FileしてCocoa Touch Classを作成Also create XIB fileにチェック
SubclassにUITableViewCellを指定
(名前は適当にExampleTableViewCellとしておきます)
するとExampleTableViewCell.swift, ExampleTableViewCell.xibが出来ると思います。
swiftファイルを確認すると確かにUITableViewCellを継承していることを確認出来るかと思います。
class ExampleTableViewCell: UITableViewCell {
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
swiftファイルは今回はいじることはないのでそっ閉じでOKです🙆
xibファイルをクリックするとStoryBoardで見たような直感的(笑)の画面になるかと思います。
まず問題ないと思いますがCustom ClassがExampleTableViewCellになっていることを確認して下さい。
であとは好きにデザインして下さい。StyleやSelectionの項目をいじるなり、Labelを追加するなり😀
次の記事でコードからXibを利用する方法について書きます。
記事書くのも疲れる🙇
2018年3月24日土曜日
StoryBoardを使わない
最近cocos2d-xとUnityでアプリ制作をしており、ふとSwiftって使ったことがないなぁと思いました🙌
スマートフォンのネイティブってLobi連携のためのAndroidJavaとかSNSサービス連携であったりブラウザ起動だったりをObject-Cで組んだり、局所的な部分でしか扱ったことがなく、一度しっかりSwiftのみでアプリを作ってみたいなと。
で、おなじみのProduct NameだったりOrganization Identifierを設定して、LanguageをSwiftにしていざCreate
すると見慣れぬMain.storyboardとLaunchScreen.storyboardというものが…
結論から言うと個人的にはこのStoryBoardは何も使えないと判断しました😇
例えるならNintendoLabo的なことしか出来ない。
アプリの性質によってはそれで十分てことはあるだろうし、非エンジニアにも扱えるって利点はあるのかもしれないですが、エンジニアもしくは今後もアプリを作っていくのであればStoryBoardは使わないのを推奨します。
ということでまずはMain.storyboardを削除します。
そしてInfo.plistのMain storyboard file base nameも削除します。
AppDelegate.swiftを開き、applicationメソッドを以下のように修正します。
ちなみにLaunchScreen.storyboardやInfo.plist内のLaunch screen interface file base nameは残しておきましょう!
ここで画面サイズ等の情報を取得しているそうです。
でStoryBoardを使う利点であるUIの直感的な配置についてはXibを利用します。
それについては次の記事で書こうかと😀
スマートフォンのネイティブってLobi連携のためのAndroidJavaとかSNSサービス連携であったりブラウザ起動だったりをObject-Cで組んだり、局所的な部分でしか扱ったことがなく、一度しっかりSwiftのみでアプリを作ってみたいなと。
- Xcode 8.3.3
- Swift 3.1
で、おなじみのProduct NameだったりOrganization Identifierを設定して、LanguageをSwiftにしていざCreate
すると見慣れぬMain.storyboardとLaunchScreen.storyboardというものが…
結論から言うと個人的にはこのStoryBoardは何も使えないと判断しました😇
例えるならNintendoLabo的なことしか出来ない。
アプリの性質によってはそれで十分てことはあるだろうし、非エンジニアにも扱えるって利点はあるのかもしれないですが、エンジニアもしくは今後もアプリを作っていくのであればStoryBoardは使わないのを推奨します。
ということでまずはMain.storyboardを削除します。
そしてInfo.plistのMain storyboard file base nameも削除します。
AppDelegate.swiftを開き、applicationメソッドを以下のように修正します。
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window?.rootViewController = ExampleViewController()
self.window?.makeKeyAndVisible()
return true
}
ちなみにLaunchScreen.storyboardやInfo.plist内のLaunch screen interface file base nameは残しておきましょう!
ここで画面サイズ等の情報を取得しているそうです。
でStoryBoardを使う利点であるUIの直感的な配置についてはXibを利用します。
それについては次の記事で書こうかと😀
2018年3月23日金曜日
Swiftのバージョンを調べる
Swiftのバージョンを調べる方法
ターミナルを起動しましょう。
ターミナル?なにそれ?って人はアプリケーション -> ユーティリティにあるので、そちらを起動
あとは以下コマンドを実行
ターミナルはexitとかで終了させちゃってください
ターミナルを起動しましょう。
ターミナル?なにそれ?って人はアプリケーション -> ユーティリティにあるので、そちらを起動
あとは以下コマンドを実行
swift --version
ターミナルはexitとかで終了させちゃってください
2016年8月25日木曜日
MonoDevelop
MacのMonoDevelopさん、日本語入力が出来るようになったのは最近のお話。
日本語対応してくれたのは素直に嬉しい限りですし、文句言える立場ではないのですが、以下のような現象が発生しております(´・ω・`)
コメントとかで「昨日は」とか入れたい場合(あくまで例です)
キーボード的にはKINOUHAと入力すると思います。
KINOUと入力して「昨日」に変換して、HAと入力すると「あ」となるのです。。。
KINOU(in) -> 昨日(out) -> HA(input) -> あ(out)
以下のように入力すれば問題ないのですけどね。。。
KINOU(in) -> 昨日(out) -> Enter -> HA(input) -> は(out)
日本語変換を確定する次の入力(space, tab, deleteなどなどを除いて)をEnterとして処理しているのか、内部的なことは分かりませんが自分の癖のせいで非常に面倒なことになっております(´・ω・`)
同じ理由で嘆いている人は見かけなかったので少数意見かもしれません。
いや、日本語対応してくれただけで喜ばなきゃいけない!文句ばっか言ってちゃいけない!
あ、あと対応する括弧にジャンプする機能が欲しいのとファイルのタブ切替えをNext/Prevじゃなくて現実のタブ基準にして欲しいです(´・ω・`)
日本語対応してくれたのは素直に嬉しい限りですし、文句言える立場ではないのですが、以下のような現象が発生しております(´・ω・`)
コメントとかで「昨日は」とか入れたい場合(あくまで例です)
キーボード的にはKINOUHAと入力すると思います。
KINOUと入力して「昨日」に変換して、HAと入力すると「あ」となるのです。。。
KINOU(in) -> 昨日(out) -> HA(input) -> あ(out)
以下のように入力すれば問題ないのですけどね。。。
KINOU(in) -> 昨日(out) -> Enter -> HA(input) -> は(out)
日本語変換を確定する次の入力(space, tab, deleteなどなどを除いて)をEnterとして処理しているのか、内部的なことは分かりませんが自分の癖のせいで非常に面倒なことになっております(´・ω・`)
同じ理由で嘆いている人は見かけなかったので少数意見かもしれません。
いや、日本語対応してくれただけで喜ばなきゃいけない!文句ばっか言ってちゃいけない!
あ、あと対応する括弧にジャンプする機能が欲しいのとファイルのタブ切替えをNext/Prevじゃなくて現実のタブ基準にして欲しいです(´・ω・`)
2016年3月21日月曜日
Skype Connection OFFLINEになってしまう問題
Skypeのバージョンは7.21で、現象発生時点で最新です。
MacBook Pro (Retina, 13-inch, Mid 2014)で、使用OSはYosemite (10.10.3)です。
現象としては…
その後にサインアウトしたのですが、バックグラウンドで通信しているのかメッセージの通知が来ました。
再度Android側操作でサインアウトして気持ち悪いのでアプリ削除。
そこからSkypr for desktopにてグループチャットが届かなくなり、ファイル受信も出来なくなりました。
個人メッセージはやり取り可能です。
その時点でSkypeが最新であることは確認していたのですが、再インストールも試して改善せず…(´・ω・`)
PC再起動もして、一年以上触っていなかったiPhoneのSkypeについてもアプリ削除。
それでも改善せず…
調べていく内に海外サイトに行き着き、以下コマンドを実行。
Skype自体はオンライン状態(前述の通り個人メッセージは可能)なのですが、OFFLINEかつ切断という結果。
/etc/hostsファイルも確認したのですが、問題なし。
Skype for WebやiOS、AndroidのSkypeでは問題なくグループチャットが届いているし、ファイル受信も可能。
Skypeの方に変にアカウントが滞在しているような状態ではなさそう。
バージョン7.20にダウングレードしても改善しませんでした…
「常に最新にする」は速攻でOFFにしました。
でもなぜか勝手にアップデートする時があるのでdmgファイルはローカルに取っておいてます…非常に不便。
コミュニケーションツールに関しては会社でも周りの人と合わせないといけないのでアレですが、Slackかchatworkの方が良さそうですね。
使い方勉強していかねば。
MacBook Pro (Retina, 13-inch, Mid 2014)で、使用OSはYosemite (10.10.3)です。
現象としては…
- グループチャットが届かない
- ファイル受信が出来ない
その後にサインアウトしたのですが、バックグラウンドで通信しているのかメッセージの通知が来ました。
再度Android側操作でサインアウトして気持ち悪いのでアプリ削除。
そこからSkypr for desktopにてグループチャットが届かなくなり、ファイル受信も出来なくなりました。
個人メッセージはやり取り可能です。
その時点でSkypeが最新であることは確認していたのですが、再インストールも試して改善せず…(´・ω・`)
PC再起動もして、一年以上触っていなかったiPhoneのSkypeについてもアプリ削除。
それでも改善せず…
調べていく内に海外サイトに行き着き、以下コマンドを実行。
/showplaces MSNP: Connection OFFLINE
/dumpmsnp MSNP: Connection Data (MSNP24): * Status: NetStateDisconnected (略)
Skype自体はオンライン状態(前述の通り個人メッセージは可能)なのですが、OFFLINEかつ切断という結果。
/etc/hostsファイルも確認したのですが、問題なし。
Skype for WebやiOS、AndroidのSkypeでは問題なくグループチャットが届いているし、ファイル受信も可能。
Skypeの方に変にアカウントが滞在しているような状態ではなさそう。
バージョン7.20にダウングレードしても改善しませんでした…
結果として…
一年近く古いバージョン7.18にダウングレードすることで直りました…(´・ω・`)「常に最新にする」は速攻でOFFにしました。
でもなぜか勝手にアップデートする時があるのでdmgファイルはローカルに取っておいてます…非常に不便。
コミュニケーションツールに関しては会社でも周りの人と合わせないといけないのでアレですが、Slackかchatworkの方が良さそうですね。
使い方勉強していかねば。
cocos2d-x本来のフレームワークが生成されない問題
起きている問題は…
cocos2d-xはver3.9を利用しています。使用OSはMacのYosemite (10.10.3)です。
あるタイミングからcocos newコマンドでプロジェクトを作成してもcocos2d-x本来のフレームワークが生成されない問題が発生しました。
Xcodeを用いて作成したプロジェクトを開いてもcocos2d_lib.xcodeprojが該当プロジェクト内に存在しない状態です。
同様にプロジェクト直下(proj.ios_macなどがあるディレクトリ)にcocos2dディレクトリがありませんでした。
ただ、ライブラリファイルはリンクしているためSpriteやRefなどは記述可能。
ヘッダファイルまでは見れるのですが、ソースファイルは見れないといった状態です。
以前までは上記した問題は起こっておらず、他利用者様と同じ構成で生成されていたのですが。。。
現象発生前後で行ったこと
- cocos studioを追加
- Android Studioに既存プロジェクトを追加
- コンパイル高速化のためにccacheを適用
ただ、念のため全て設定や定義を戻し、再度cocos newを実行………改善されず(´・ω・`)
実際、実行は出来る?
実行は可能でした。そこで実際cocos2d-x関連のファイルはどこを参照しているのか、を調査しました。Xcode -> PROJECT, TARGETS -> Build Settings -> Search Paths -> Header Search Paths, Library Search Paths, Framework Search Paths
すると以下ディレクトリのファイルを参照していました。
/Applications/Cocos/frameworks/cocos2d-x-X.X
なぜcocos studioのディレクトリを参照しているのか、その定義があるのかについても改めて調査しましたが、どこにも見当たらず…
最新バージョンver3.10だとどうなる?
調査時点でcocos2d-xの最新バージョンver3.10がありましたので、それを適用してみようと思いました。setupも再度実行、bash_profileが適切に書き換わっていることも確認し、再読込み。
cocos newしてみましたが現象変わらず…(´・ω・`)
一旦諦め、リフレッシュ後に再度調査。
cocos newしてみたら正常にフレームワーク含め生成されました…
結局何が原因だったのか、何故解決したのかは不明…
登録:
コメント (Atom)