2017年9月21日木曜日

iOS11で不具合/ツイートできない

あくまでもiOS11にしたらアプリがうまく動かなくなったってことね。

ツイッターに投稿しようとしたら、

if SLComposeViewController.isAvailable(forServiceType: SLServiceTypeTwitter) { }
がfalseになっちまいまして…orz
むろん今まではうまくいってた。

iOS11になった際に、自作アプリへのツイッターアクセスの設定がリセットされたのかしら?

調べたら、iOS11でいきなり非推奨どころか使用不可になってるみたい! ギョギャギャギャギャギャギャ!
どうやら、他社のサービスは他社のやり方でやれ、Appleはしらんわ…ということらしい。まあセキュリティの問題とかいろいろあるせいとは思うけど、めんどくさくなるのは勘弁してほしい。
ツイッター公式のTwitter kitというSDKがあって、今後はそっちを使わねばいけなくなるようだ。

詳しくは上のサイトのやり方に従って欲しいが、
  1. ツイッターにサインインしてアプリ情報などを入力
  2. Twitter Kit SDKをダウンロードしてXcodeのプロジェクトにインストール
  3. Xcodeのプロジェクトに必要なFrameworkを追加し、設定を追加
  4. ソースコードを編集
という手順になるようだ。
めんどくさいけど、百歩譲って、今までのiOSのTwitterの投稿ダイアログみたいなちっちゃくて使いにくいものから解放されるんならいいな。

今日は寝るので、また明日やってみた結果を追記する。

2017年9月20日水曜日

Swift 4リリース

Xcode 9でさっそくSwift 4がリリースされた。
2.x → 3 ほどの大きな変更はないと思うが、気付いた点があったら追記していく。

@objc推論の廃止

Dependency Analysis Warning
The use of Swift 3 @objc inference in Swift 4 mode is deprecated. Please address deprecated @objc inference warnings, test your code with “Use of deprecated Swift 3 @objc inference” logging enabled, and then disable inference by changing the "Swift 3 @objc Inference" build setting to "Default" for the "アプリ名" target. 
Swift 4モードでのSwift 3 @objc推論の使用は廃止されました。
推奨されない@objcの推論のWarningに対処し、「廃止されたSwift 3 @objc推論の使用」ロギングを有効にしてコードをテストし、 「アプリ名」 targetの 「Swift 3 @objc Inference」ビルド設定を 「Default」にしてください。

——Swift 3で作ったコードを開いたら出た。よくわからんのだけど、Objective-CのクラスとかをSwiftで扱う時に型を推定してくれてたのかな? んで、それが廃止になって、型変換とかを自分で明示的にやれ…とかそんな意味か?
別にObjective-Cのコードとか使ってなかったけど、Xcode 8でデフォルトでそういう設定だったんだろう。それなら自動で直してくれりゃいいのに。グチグチ。
ここをDefaultに変えるとWarningが消える
Build Setting、TARGETSにはアプリ名とアプリ名+Testsの二つがあるが、その両方にSwift 3  @objc inferenceの設定があるので、両方変えてやる必要がある。

#selectorの書き方?

Timer.scheduledTimer(timeInterval: 0.5,
                  target: self,
                selector: #selector(IdleEvents.filterUpdate(timer:)),
                userInfo: nil,
                 repeats: true)

こういうコードをSwift 3で書いてたんだけど、#selectorのところに以下のエラーが。
2番目のエラーにはFixってボタンが出るんでそれを押すと消えるんだけど、一時的なものらしく、また出たり、@objcってのをコード中の変なところに挿入されたり、なんだかよくわからん!
Argument of '#selector' refers to instance method 'filterUpdate(timer:)' that is not exposed to Objective-C
Add '@objc' to expose this instance method to Objective-C

どうやら、#selectorで呼び出す関数、メソッドの頭に「@objc」ということらしい。
@objc func hogehoge() { … }

んで、そんなこんなやってたら自作のクラスにExpected declarationというエラーが出るようになった。
調べたらコードの最後に「@objc」が付けられてた。さっきのFixボタンがいい加減なところに挿入しやがったんだな。

Xcode 9の変更点

2017/9/20にアップデートされたXcode 9について、Mac AppStoreの説明文の訳。

Xcode 9には、iOS11、watchOS 4、macOS High Sierra 10.13用のSwift 4とSDKが含まれています。
  • リファクタリングにより、Swift、Objective-C、C、およびC ++コードの構造を簡単に変更できます。
  • コードエディタは驚くほど速く応答性があり、Markdown構文のネイティブサポートを追加します。
  • Fix-itsはワンクリックでコードを複数改善し、必要なプロトコルメソッドを追加することもできます。
  • 新しいソースコントロールナビゲータと統合されたGitHubアカウントにより、チーム全体のコードを簡単に管理できます。
  • ネットワーク上のデバイス上のiOSおよびtvOSアプリケーションのワイヤレスインストールとデバッグ。
  • シミュレータは実際のデバイスのように見え、動作し、一度に複数のデバイスをシミュレートできます。
  • iOSのPlaygroundテンプレートは、XcodeとiPadのSwift Playgroundの両方で動作するドキュメントを作成します。
  • Find navigatorは非常に高速で、結果はすぐに表示されます。
  • プロジェクトナビゲータは自動的にファイルとグループをFinderとソースコントロールと同期させます。
  • XcodeサーバーはもはやmacOSサーバーを必要とせず、Xcode環境設定で完全に設定することができます。
  • 次世代のビルドシステムは、多くのプロジェクトを構築するとき(オプションで有効)、信頼性とパフォーマンスを向上させます。
  • Swift 4コンパイラは、Swift 3コードを構築して、一度に1つのモジュールで段階的な移行を可能にします。
  • 最新のSDKには、機械学習のためのCore ML frameworkと、拡張現実のためのARKitが含まれています。
えーと、Swift 4がもうリリースされたのだね Σ(((°Д°;))))ガクガク

2017年9月19日火曜日

URLスキーム/URLで地図アプリを開く

やりたいこと

緯度経度の位置情報を持ったリンク(たとえばTwitterのツイートとか)を押すと、自動的に地図アプリを起動して指定した場所を表示してくれるようにしたい。

こういうのをURLスキームという。

2種類のスキーム

Appleのマップ用

iOSの場合のURLスキームは以下のものとなる。
http://maps.apple.com/maps?パラメータ

これはApple純正マップ.appがインストールされているデバイスではマップ.appが優先的に起動し、非インストール機(WindowsやAndroid含む)ではGoogleMapが起動される(GoogleMapアプリがなければブラウザ上で)。

GoogleMaps専用

詳しくは公式ガイドページ
マップ.appがインストールされたデバイスでもGoogleMapを起動することもできる。
https://maps.google.com/?パラメータ
https://www.google.com/maps/preview/パラメータ

こちらはMacなら直接ブラウザで、iOSのTwitterアプリならそれの子プロセスとしてWebビューが開く。
iOSの場合、右上のアイコンからSafariで開き、さらにSafariで開いた画面上部に"Google Maps" Appで開くという表示から、GoogleMapsアプリで開くこともできる(アプリがインストールされていればだが)。
試してないがWindowsでもAndroidでも同じような感じだろう。
GoogleMapsアプリで開くまでが少し手間だが、難しいことではないし、たいていは子プロセスとしてのWebビューで事足りるだろう。

comgooglemaps://?パラメータ
などという方法もあるが、こちらは直接ブラウザを経由せずにGoogleMapアプリを開くためのもので、ツイートに直接書き込んでもURLとして認識されない。
ブラウザのURL欄に書いた場合、iOSでは直接GoogleMapsアプリが開けたが、アプリがないMacだと当然ダメ。素直にhttps〜形式の方がいい。

どっちの方がいいか

機能としてはGoogleMapsの方がStreetViewがあったりと高機能なので、当面は後者のURLスキームの方が良さそうだ。
同じ緯度経度、表示範囲(拡大率)を維持したまま相互を切り替えられるといいんだけどな。

2017年9月17日日曜日

Objective-CのコードをSwiftに移植

Swift3にもなって、そろそろObjective-Cで作ったアプリをSwift化した方がいいと思うようになった。

メンテナンスのたびにObjective-Cを思い出しながら作業するのも面倒。
いつアップルが「もうObjective-Cのサポートやめるから、これからは審査通さんからね」って言い出しかねない。
なんだかんだ言ってObjective-Cのコードはごちゃごちゃしてることが多い。ヘッダファイルやimportも必要だし。

そんなわけで今さらだが、Swiftに移植してみることにした。

以下、調べたことのメモ

  • 同じプロジェクト内でクラスのファイル(ViewController.h、同.mとか)ごとに移行可能。
  • クラスのファイル名は拡張子が別になるので、Objective-CとSwiftで同居可能。(ViewController.h、同.m、同.swift)
  • 最初にSwiftファイルを追加するときに「bridginf header」というファイルを作るかどうか聞かれるので、作っておく。

手順

移行するクラスファイルと同名のSwiftファイルを作ってコードを移植。
Objective-Cの.hと.mのファイルを削除。
Storyboardに結びついてるならCustom ClassのModuleがNoneになってるので、そこをプロジェクト名に直す。(最初にCurrentに直すとも?)
IBOutletやIBActionの結びつきを直す。

Objective-C、Swift相互の呼び出し

Objective-CのクラスからSwiftのクラスを呼ぶには、呼び出し元のObjective-Cのファイルに
#import "アプリ名-Swift.h"
を追加。
逆にSwiftからObjective-Cを呼ぶには作っておいた「プロジェクト名-Bridging-Header.h」に呼び出し先のObjective-Cファイルをimportする。

でいいらしい。

AppDelegateの移植

AppDelegateも同様に移植する。
Objective-CではSupportingFilesフォルダ中にmain.mが作られてるけど、これが残ってるとかえってエラーになるので、削除する。
Swiftの普通のAppDelegateを参考にすりゃわかるけど、class AppDelegateの前に@UIApplicationMainってのを書いてやる。
多分これで最初に呼ばれるファイルに指定されるんだろう。

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

2017年9月14日木曜日

TableViewを使う


Xcode右下の部品一覧からUITableViewControllerをStoryboardにドロップすると簡単なんだけど、なぜかTableViewにConstraintsが設定できない。
一番上のCellがステータスバーに重なってしまうなどよろしくない。

普通のUIViewControllerにUITableViewをドロップし、UIViewの子Viewにすればこれは回避できる。
その際はTableViewとViewControllerをdelegateとdataSourceで結んでやること。(Storyboardの黄色いアイコンまで右ボタンドラッグ)

TableViewのStoryboard IDとか、TableViewCellのRestoration IDとかも設定した方がいい。

また、ViewControllerに結びつけるSwiftのクラスはUIViewControllerを親クラスとし、UITableViewDelegateと同DataSourceを設定してやる。

class TableViewController: UIViewController, UITableViewDelegate,UITableViewDataSource {
}

さらに、delegateメソッドはoverrideにしない。

2017年9月12日火曜日

乱数の関数メモ

いろいろある乱数発生の関数をメモ

arc4random()
返り値の型はUInt32なので、Swiftみたいに型をきっちり指定してやらないといけない言語の場合、ちょい面倒。

arc4random_uniform(__upper_bound: UInt32)
0〜引数-1までのランダムな整数を返す。
arc4random_uniform(10)なら0〜9まで。使い勝手良さげ。


drand48()
返り値の型はDoubleらしい。
0.0〜1.0の間の負でない倍精度の浮動小数点値を返す。
UIColorのrgb値が0.0〜1.0とこれにドンピシャガンガンなので、いちいちarc4randomとか使わんでいい。
今知ったばかりなんでよくわかってないw

UICollectionViewを使う際の注意

つまった点のメモ。
右クリックのドラッグで黄色のアイコンと結んでやる
StoryboardでUICollectionViewの部品をUIViewControllerの上にドロップするのはいい。
その後、ドロップしたそれをマウス右ボタンクリックでそのStoryboardの上にある黄色いアイコンにドラッグし、ポップアップしたメニューからdataSourceを選んで接続してやる必要がある。
これに気づかずに「コード合ってんのに表示されねー」ってだいぶ悩んだ。

あとはUICollectionViewCellのReusableViewのIDの設定とか、protocolになってる
UICollectionViewDelegate, UICollectionViewDataSource
をclassのところで設定してやるとか、その辺がつまづきやすい。

ところで、UIViewControllerにUICollectionViewを貼るよりも、XcodeのUI部品一覧の中にUICollectionViewControllerってのがあるから、それをStoryboardにドラッグした方がdataSourceとdelegateの設定もされるから早いみたいね ^^;

2017年9月6日水曜日

StoryboardでScrollViewのコンテンツを配置

UIScrollView上に配置するUIをStoryboardで配置しようとすると、iPhoneやiPadのサイズからはみ出したUIが隠れてしまう。
ScrollViewの上にMapViewと紫色のViewが乗ってる

そこで、そのStoryboardのViewControllerを選択し、SizeInspectorのSimulated SizeをFreeformにし、Height(もしくはWidth)を必要な値に変更してやれば、Storyboardがその長さまで広がってくれるのでUIの配置が簡単にできるようになる。


MapViewに表示できるpinの数

1000個くらい一度に表示できないものか、できるなら表示速度はどんなもんじゃろうと試してみた。

横並びの制限?

経度1度ごとに横に並べるようにしたら、なぜか411個という中途半端な個数が最大だった。
なぜか411個が限界

ランダム配置なら制限なし?

しかし世界中のランダムな位置に刺すようにしたところ、1000個でも表示できた
1000個でもいけた
昔のパソコンのスプライトじゃあるまいし、横位置に並べられる制限があるのかしら?

なお表示速度はどちらも一瞬で、目立った遅延もないようなので気にしなくて良さそう。

10,000個でも大丈夫

10,000個にもチャレンジしたら、表示できたが、さすがにspanを広くしてpinがいっぱい表示されるようにしたら重くなった。(iPad Air2)
でもちょっと引っかかる程度で、実用上さほど問題あるとも思えなかった。spanを狭く取ればスイスイだし。
10,000個もpinを表示する機会は滅多にないよね。
10,000個でもいけたがちょっと重い


override func viewDidLoad() {
        super.viewDidLoad()
        
        //pin1000個追加
        var annotationArr = Array<MKAnnotation>()
        for i in 1...1000 {
            let anno = MKPointAnnotation()
            let longi = Double(arc4random() % UInt32(360)) - Double(180)
            let lat   = Double(arc4random() % UInt32(180)) - Double(90)
            print(i)
            anno.coordinate = CLLocationCoordinate2DMake(Double(lat), Double(longi))
            anno.title = "経度:\(longi) 緯度:\(lat)"
            anno.subtitle = "番号 \(i)"
            annotationArr.append(anno)
        }
        self.myMapView.addAnnotations(annotationArr)

        //1000番目のpinの位置をマップのデフォルト位置に
        let lat = annotationArr.last?.coordinate.latitude
        let lng = annotationArr.last?.coordinate.longitude
        let coordinate = CLLocationCoordinate2DMake(lat!, lng!)
        let span = MKCoordinateSpanMake(0.05, 0.05) //表示範囲(拡大)
        let region = MKCoordinateRegionMake(coordinate, span)
        self.myMapView.setRegion(region, animated: true)

    }


ちなみに以前勉強した時はMKPointAnnotationを使わずにカスタムクラスを作ってannotationを管理するようにって読んだんだけど、単純に表示するだけならMKPointAnnotationで事足りるよね? よくわかんないけどいいか。

色を変えてみる

1000個表示でも少し重い
ピンの色を変えるにはMapViewのdelegateメソッドを使う必要がある。

ピンの緯度経度、タイトル/サブタイトル、色やアイコンのデザインまで一括してプロパティに持つクラスがありゃいいのにと思うけど、Appleの技術者様の考えることはわからない。
しょうがないので、みんなカスタムクラスを作ってるみたい。

表示は少し重くなる。ピンを表示するごとにdelegateメソッドが呼ばれるせいだろう。
数が少なければ気にならないと思う。


//pin1000個追加の後あたりに以下を追加
self.myMapView.delegate = self

さらにメソッドを追加。
    //pinのデザインを変えるにはdelegateメソッドを使う
    func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
        let annoView = MKPinAnnotationView()
        annoView.annotation = annotation
        let r = Float(Double(arc4random() % 10) / 10)
        let g = Float(Double(arc4random() % 10) / 10)
        let b = Float(Double(arc4random() % 10) / 10)
        annoView.pinTintColor = UIColor.init(colorLiteralRed: r, green: g, blue: b, alpha: 1.0)
        annoView.canShowCallout = true
        
        return annoView
    }

画像を変えてみる

画像2種類+色を変えたピン
意外と軽い
今度は画像を変更して見たところ、動きが軽い。
色を変えないピンよりは引っかかるが、色を様々に変えたものよりは軽いのだ。
delegateメソッドを繰り返し呼ぶのがボトルネックになっているのではなく、新たに色が違う画像を生成するか、キャッシュされた画像を再利用するかの点で違いが出てるのかも?
もっと画像の種類を増やすと違いが出てくるだろう。

なお、画像の中心(9*9の画像なら5,5の位置)が設定した緯度経度の位置になるようだ。
同じ緯度経度のデフォルトのピンと重ねてみるとよくわかる。

2017年9月3日日曜日

ARとモーションセンサー覚書

勉強中のARプログラミングと、CMMotionManager( )を使ったモーションセンサー等についてメモっとく。

ジンバルロック

詳しくはググってほしいけど、3軸の姿勢センサーの2軸の動きが重なってしまい、姿勢が正しく計測できなくなること。
姿勢センサーを使ったアプリで、時々「∞の字に動かしてください」とか出るのはこれをリセットするためか?

Pitch, Roll, Yaw値の範囲

CMMotionManager( )のAttitudeとして得られるそれぞれの値の範囲(度数法の角度で)
  • Pitch
    • -90 〜 0 〜 90
    • デバイスを机に画面を上で寝かせた状態が0
    • 垂直に起こした状態が90
    • デバイス上部を垂直に下にした状態が-90
  • Roll
    • -180 〜 0 〜 180
    • デバイスを机に画面を上で寝かせた状態が0
    • 左に傾けて起こしていくとマイナスになって、完全にひっくり返すと-180
    • 右に傾けて起こしていくとプラスになって、完全にひっくり返すと180
  • Yaw
    • -180 〜 0 〜 180
    • デバイスを机に画面を上で寝かせて西を向けた状態が0
    • 反時計回りでプラスになって、東で180
    • 時計回りでマイナスになって、東で-180

2017年8月20日日曜日

UITextViewのセンタリング

やりたいこと

ImageViewで描かれた吹き出しの中にTextViewを貼っている。
吹き出しの大きさが変更された時、中のテキストをそれに合わせ、吹き出しのできるだけ中心部分にセンタリングしたい。

必要なこと

TextViewのframeでなく、中のテキストが実際に表示されてる部分のrectを求め、それを元にセンタリングする。
CSSとかのpaddingに当たる値ですな。

TextViewの中のテキストの画面に表示されてる部分のみのrectはNSStringの以下の関数で得られる。
当然得られる値はTextViewのframe.sizeよりも小さくなる。

コード中のfdってのは俺のコードの都合なので無視して。
要は調べたいtextViewがどういうrectで、中のテキストはどんなフォント(サイズも含む)で画面に描画されるかを渡して調べてもらうわけだろう。

let rect = NSString(string: (fd!.textView.text)!)
                .boundingRect(with: (fd?.textView.frame.size)!,
                options: NSStringDrawingOptions.usesLineFragmentOrigin,
                attributes: [NSFontAttributeName : fd?.textView.font! as Any], context: nil)


textViewのframeサイズから得られたrectの値を引いて2で割れば上下/左右の均等なpaddingの値が求まる。
それをtextView.textContainerInset.〜に入れてやればいい。
textView.contentInset.〜と書かれてるサイトもあるけど、textContainerInsetじゃないとうまくいかないので注意。
contentInsetとはUITextViewの中にあるUIScrollViewに対するInsetだそうである。

var topPadding = (fd!.textView.bounds.size.height - rect.height * fd!.textView.zoomScale) / 2
topPadding = topPadding < 0.0 ? 0.0 : topPadding
var leftPadding = (fd!.textView.bounds.size.width - rect.width * fd!.textView.zoomScale) / 2
leftPadding = leftPadding < 0.0 ? 0.0 : leftPadding
//containerInset.topleft(上と左の余白)を設定
fd!.textView.textContainerInset.top = topPadding
fd!.textView.textContainerInset.bottom = topPadding / 2
fd!.textView.textContainerInset.left = leftPadding
fd!.textView.textContainerInset.right = leftPadding / 2

本来ならtopとbottom、leftとrightは同じ値を入れるべきだが、なんか微妙にテキストの位置が偏るみたいだったので、bottomとrightは値を半分にしたり、いろいろ変えてテストしてる。最適な値を探してみてほしい。
いいんだよ、理論がどうであろうと、見た目ちゃんとしてればw
また、描画の関係で文字が書かれるまでの空白とか少しできるけど、いいの。完璧じゃなくても。

参考サイト

2017年8月9日水曜日

変なメッセージ/dyld: Library not loaded:

昨日、Macの不調からかキーチェンアクセス中のiOS Develop証明書が消えてしまったらしく、頑張って再作成した。

その後、ちゃんと動作することを確認したプロジェクトが、今日になって以下のメッセージを出して落ちるようになった。

dyld: Library not loaded: @rpath/libswiftAVFoundation.dylib

ほんとはもっと長く続いてるんだけど、要するにライブラリがロードできないらしい。
ネットで調べてプロジェクトの設定をいじってみたけど直らない。一つだけじゃなく、他のいくつかのプロジェクトが同じ状態。

結局、プロジェクトをCleanしたらどうかという情報があったのでしてみたら、あっさり直ってくれた。

昨日証明書が消えた状態で起動して状態を見ていたプロジェクトだったから、そのせいだろうか。証明書再発行後にはちゃんと動くことを確認したんだけどな。
解せねえ…。

2017年8月8日火曜日

Revoke Certificate/証明書が無効に!?

晩飯食って戻ってきたらMacが再起動してて、OSのインストーラが立ち上がっていた。
なんのはずみか知らないが、前にも2度ほどあり、その都度もう一度再起動したら正常に起動してくれた。
ただし今回はTwitterのアカウントがKeyChainから消えてしまったらしく、再度入力する羽目に。ちょっと怖い。

そのままXcodeで作りかけのアプリをビルドしようとしたら、以下のメッセージが出た。

証明書を取り消すアカウントにはすでにこのマシンの署名証明書がありますが、キーチェーンには存在しません。 新しい証明書を作成するには、まず既存の証明書を取り消す必要があります。 
Cancelしても改善されないので、試しにRevoke(取り消し)を押してみたら、すぐにApple Developerから「証明書無効になったから再作成せなあかんで」とメールが来た。
どうもさっきのMacの再起動によってTwitterアカウントだけじゃなくてXcodeの情報もKeyChainから消えてしまったっぽい。

GeneralのStatusを見てもこのとおり。
Revokeボタンを押してみたらRepairとかなんとか出て処理してるので、これで直るのかと思ったがまた同じ状況に。

Apple DeveloperのiOS Certificatesでいくつかある証明書を確認。べつに有効期限も切れてないし、Invalidとかなってない。
一応そいつをDownloadして、クリックで勝手にキーチェーンアクセス.appが開くので、これで登録されるのかと思ったが、やっぱり状況変わらず。

ネットで調べると作り直す際はApple Developerの証明書をRevokeしてもいいみたいなので試してみたい。

キーチェーンアクセスの証明書で、有効期限が切れているとして❌印がついてる証明書を削除。
それでもだめなので、iPhone Developerと書かれてる証明書(有効期限内)がいくつもあったのを全部削除。しかし状況変わらず。
XcodeでRevokeし、Repair処理をするとまたその証明書が復活していたが、やはり状況変わらず。

残された手段はApple Developerの証明書をRevokeするのみ。
「証明書を取り消しちゃってええのんかぁ?」と赤いボタンのメッセージが出るけど、俺は男だ勇気を出した。

そしたら「この証明書は、『発行済み』状態ではないため、取り消すことはできません。」だって。ますますわからん。
試しにもう一度Revokeしてみたら、今度は消えちゃったよ。なんだよ、この挙動の不統一は!

今消したのはDevelopmentの証明書なので、そこから作り直せるだろう。
下の方にあるCertificate Signing Requestを押す。

一番上のiOS App Developmentを選べばいいんだと思う。

次の画面にはこんなことが書いてあった、英文で。
その通りにしてみる。
手動で証明書を生成するには、Macから証明書署名要求(CSR)ファイルが必要です。 CSRファイルを作成するには、以下の手順に従ってKeychain Accessを使用してCSRファイルを作成します。
CSRファイルを作成します。
Macの「アプリケーション」フォルダで、「ユーティリティ」フォルダを開き、「キーチェーンアクセス」を起動します。
[キーチェーンアクセス]メニュー> [証明書アシスタント]> [認証局に証明書を要求]を選択します。(そうすると証明書アシスタントが起動する)
[証明書情報]ウィンドウで、次の情報を入力します。
[ユーザ電子メールアドレス]フィールドに、電子メールアドレスを入力します。
[共通名]フィールドに、秘密鍵の名前(例:John Doe Dev Key)を作成します。
[CA電子メールアドレス]フィールドは空のままにしてください。
「要求」グループで、「ディスクに保存」オプションを選択します。
[Keychain Access内で続行]をクリックして、CSRの生成プロセスを完了します。

「続ける」と証明書要求のための「CertificateSigningRequest.certSigningRequest」ファイルの保存先を聞いてくるので、保存する。
それをApple Developerの方からアップロードする。


すぐに証明書ができるので、ダウンロードする。

ダウンロードしたios_development.cerをダブルクリックするとキーチェーンアクセスが起動して証明書に登録される。
しかし状況は同じまま!
最後の手段でMacを再起動したら直った!!

なんでこんなことになったんだろうね? Macが勝手にOSインストーラーが起動しちゃったくらいだから、その時に変なことなったんだろう。
んで、うちのMacとApple Developerをつないでる証明書が無効になっちゃったもんだから、作り直す羽目になったと。

もうひとつAppStoreで販売するためのDistributionの証明書ってのもあるけど、こっちも同じ状態になってるのかね? まあなんとなくやり方わかったんで、今度トラブったら同じように試してみる。

2017年8月2日水曜日

ARkitのクラス

iOS11から搭載されるARkitのクラスの情報の概要。
まあよくわからんのだけれども…。

拡張現実感(Augmented reality:AR)は、デバイスのカメラからのライブビューに2Dまたは3D要素を追加して、それらの要素を現実の世界に生息するように見せるユーザーエクスペリエンスを記述します。
ARKitは、デバイスのモーショントラッキング、カメラシーンキャプチャ、高度なシーン処理、および便利さの表示を組み合わせて、ARエクスペリエンスを構築する作業を簡素化します。

重要

ARKitには、A9以降のプロセッサを搭載したiOSデバイスが必要です。
あなたのアプリをARKitをサポートするデバイスでのみ利用できるようにするには、アプリのInfo.plistのUIRequiredDeviceCapabilitiesセクションにあるarkitキーを使用します。
拡張現実感がアプリの副機能である場合は、isSupported プロパティを使い、現在のデバイスが使用するセッション構成をサポートしているかどうかを判断します。

最初のステップ

ARSession class

拡張現実体験に必要なデバイスカメラとモーション処理を管理する共有オブジェクト。

構成(Configurations)

class ARSessionConfiguration

デバイスの向きのみを追跡する基本構成。
——デバイスの傾き(回転)に関してのみで、位置に関しての情報(デバイスを左に動かしたとかそういうこと)は扱わない。

class ARWorldTrackingSessionConfiguration

デバイスの向きと位置を追跡し、デバイスカメラが認識する実際の表面を検出する構成。
——デバイスの傾き(回転)と位置に関しての情報(デバイスを左に動かしたとかそういうこと)の双方を扱う。

標準ビュー(Standard Views)

Building a Basic AR Experience

ARセッションを設定し、SceneKitまたはSpriteKitを使用してARコンテンツを表示します。

class ARSCNView

3D SceneKitコンテンツを使用して、カメラビューを拡大するARエクスペリエンスを表示するためのビュー。

class ARSKView

2D SpriteKitコンテンツを使用して、カメラビューを拡大するARエクスペリエンスを表示するビュー。

カスタムビュー(Custom View)

Displaying an AR Experience with Metal

カメラ画像のレンダリングと位置追跡情報を使用して、オーバーレイコンテンツを表示することにより、カスタムARビューを構築します。

実世界の物体と位置(Real-World Objects and Positions)

class ARAnchor

ARシーンにオブジェクトを配置するために使用できる、実際の位置と方向。

class ARPlaneAnchor

ARセッションで検出された、実際の平面の位置と向きに関する情報。

class ARHitTestResult

ARセッションのデバイスカメラビュー内のポイントを調べることで見つかった、実際のサーフェスに関する情報。

カメラとシーンの詳細(Camera and Scene Details)

class ARFrame

ARセッションの一部としてキャプチャされた、ビデオ画像および位置追跡情報。

class ARCamera

ARセッションにおけるキャプチャされた、ビデオフレームのカメラ位置および撮像特性に関する情報。

class ARLightEstimate

ARセッション内のキャプチャされた、ビデオフレームに関連する推定シーン照明情報。

2017年7月13日木曜日

CollectionViewのCellの中身を更新

CollectionViewのセルをタッチしたら画像を変更するとか、タッチしたセルだけ選択された印のチェックマークをつけたりする方法。

まず、CollectionViewはTableView同様、最初に読み込まれるときにdelegateメソッドで一気に書かれるのが基本。

セルがタッチされたときに呼ばれる以下のdelegateメソッドに記述することで、特定のセルだけを内容変更することができる。
ただし、この中で直接セルの中の部品をいじってもダメなので、ここでは後述するdelegateメソッドの中で変更するように変更内容を入れる配列(ここではcellIsChecked)などをいじるだけとなる。

//セルが選ばれた時に呼ばれるdelegate
func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool {
    //選ばれたセルのcheckBtnのチェックを反転
    if cellIsChecked[indexPath.row] {
        cellIsChecked[indexPath.row] = false
    } else {
        cellIsChecked[indexPath.row] = true
    }
    
    //セルの中身を更新したら、Cellを更新しないと反映されない
    collectionView.reloadItems(at: [indexPath])
    
    return true

}

セルの中身の変更はあくまでdelegateメソッド内で

collectionView.reloadItems(at: [indexPath])を実行することで、以下のdelegateメソッドが順番に呼ばれる。
つまり、あくまでも変更は以下のメソッド中で行うということになる。
ただし、最初に読み込まれる時と違い、下のメソッドはreloadItemsで指定したindexの分だけが呼ばれる。

//セクションの数を指定
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int)

//セルの中身を指定
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath)
{
    //選ばれたセルをセル番号で取り出す
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! PhotoCollectionViewCell
    var title:String
    if cellIsChecked[indexPath.row] { title = "" } else { title = "" }
    cell.checkBtn.setTitle(title , for: .normal)
        
    return cell

}


collectionView.reloadItems(at: [indexPath])
のかわりに

collectionView.reloadData()
で全体を書き換えることもできるが、処理が重いのでオススメはできない。

2017年7月12日水曜日

Documentsフォルダ内の画像ファイル読み書き

アプリ内にあるDocumentsフォルダに対して、画像ファイルを読み書きする方法。

Swift3ではURL(Swift2.xまではたしかNSURL)型で保存先情報を持つのだが、そのURLをそのまま引数に書いてやってもうまくいかない。
myURLに入っているなら、myURL.pathというプロパティで指定してやる。
引数はString型のようなのでmyURL.descriptionとやってみたがダメだった。

実機で試した場合のpathとdescriptio

ファイルpath
 /var/mobile/Containers/Data/Application/47DCD124-F9A4-4953-9B81-696DA790CCED/Documents/20170711055328142.jpg

ファイルdescription
 file:///var/mobile/Containers/Data/Application/47DCD124-F9A4-4953-9B81-696DA790CCED/Documents/20170711055328142.jpg

頭のfile:///の有無だけのようだ。

書き込み

//Documentsディレクトリのpathを得る(返り値はArrayで、index0がそれ)
let docPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
//StringappendingPathComponentがないのでURLに変換
let fileURL = URL(fileURLWithPath: docPath).appendingPathComponent(fileName)
//JPGに変換
let imageData = UIImageJPEGRepresentation(savePhoto, 1.0)
//画像書き込み(URLのpathを引数に)
//write(to:)はエラーを投げる関数なので、do-catch文が必要
do {
   //do-catchを使ってるので書込みエラーが起きるとcatchに移ってくれる
     try imageData?.write(to: fileURL, options: .atomic)
   //書き込み成功時の処理
   (省略)
   } catch let error {
   //書き込み失敗時の処理
     print("画像保存失敗 \(error)")
   }

読み込み

エラー処理なんかはしてない。

//Documentsディレクトリのpathを得る
let filePath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
//その後にファイル名を追加
//(String型のfileWithPathのメソッドがSwiftにないので、一度URL型に変更)
let fileURL = URL(fileURLWithPath: filePath).appendingPathComponent("ファイル名")
//.pathプロパティを引数に画像読み込み
let uiImage = UIImage(contentsOfFile: fileURL.path)