OSSのようなFramework ProjectをPlaygroundで動作確認する方法
前説
OSS内にPlaygroundが含まれている場合、そのPlaygroundを弄って動作を確認することは容易です。しかし、Playgroundは、含まれていないけどPlayground上で動作を軽く確認したい!
軽く確認するためにTest Project作ってPodsやCarthageでOSS引っ張ってくるのはしんどいということ…ありませんか?
もしくは、オリジナルの神Frameworkを作ったから、Playground上で動作確認したい…そういうことありませんか?
そういった軽く動きをPlayground上で確認する方法をご紹介します。
材料
今回は、下記環境を使って説明していきます。 * Almofire 4.7.2 * Xcode 9.3
1. Workspaceを作る
既にFramework Projectの方で*.xcworkspace
(画像赤い点線) が用意されている場合、それが使えるので「2.」へ。
WorkspaceがないProjectは、Workspaceを作ります
- Workspaceを作りたいFramework Projectを開く
- Menuから
File
>Save As Workspace...
を選択 - Workspaceを保存する
2. Playgroundを作り、Workspaceに追加する
Playgroundを作り、Workspaceに追加してProject上で参照できるようにします。
*.xcworkspace
をXcodeで開く- Menuから
File
>New
>Playground...
を選択 - Playgroundを保存する
- 開いているWorkspaceに対してMenuから
File
>Add Files to "Project Name"...
を選択 - 「2.」「3.」で作成したPlaygroundを選択
3. Framework Projectをbuildと動作確認
今回Playground上で実行させるコードは下記で、簡単に説明すると英語のwikipediaからJSONで情報を取ってくる内容になっています。
import Alamofire print("=== start ===") // url var url = "https://en.wikipedia.org/w/api.php" // parameters var parameters: Parameters = [ "action" : "query", "format" : "json", "titles" : "oryzae" ] Alamofire.request(url, method: .get, parameters: parameters) .responseJSON { response in print(response) } print("=== end ===")
しかし、この時点ではまだ下記のようにerrorが出て、Framework Projectで実装されたコードをPlayground上で実行できません。
Playground上でimportできるようにFrameworkを作成
- 任意のSimulatorを選択してbuild
※Generic iOS Device
の場合、build errorになるので必ずSimulatorを選ぶこと - buildによりFrameworkが作成され、Playgroundでimport&実行が可能に
EX. Playgroundで非同期処理も実行
Playgroundでerrorが表示されていないので、Alamofireも実行されている!やったね✌️…と、よくみるとAlamofireのresponse内のprint
がログに表示されていない。
実はPlaygroundは、上から順に同期処理を行い、最後の行に到達したら処理を終了するため、非同期処理は実行されない。
非同期処理も行わせるためには、下記の// 追加
とあるコードをPlaygroundに追加する必要がある。
import Alamofire import PlaygroundSupport // 追加 // 非同期処理を実行させる PlaygroundPage.current.needsIndefiniteExecution = true // 追加 print("=== start ===") // url var url = "https://en.wikipedia.org/w/api.php" // parameters var parameters: Parameters = [ "action" : "query", "format" : "json", "titles" : "oryzae" ] Alamofire.request(url, method: .get, parameters: parameters) .responseJSON { response in print(response) } print("=== end ===")
PlaygroundPage.current.needsIndefiniteExecution
は、名前の通り非同期処理の実行が必要かどうかを持つPropertyである。default値はfalse
なので意図的にtrue
にしてやる必要がある。
これで、非同期処理含めFrameworkの処理をPlaygroundで実行出来たね。
iTunes Music Library.xmlのタグ名と項目の値のメモ
iTunes Music Library.xml
- iTunes Music Library.xmlとは
- 未入力の項目は、keyが存在しない
- bool値は
<true/>
のタグで表される
タグ | 型 | 値 | 補足 |
---|---|---|---|
Track ID | integer | 5944 | |
Size | integer | 36089400 | |
Total Time | integer | 278293 | |
Disc Number | integer | 1 | Discの分子 |
Disc Count | integer | 2 | Discの分母 |
Track Number | integer | 1 | 曲数の分子 |
Track Count | integer | 12 | 曲数の分母 |
BPM | integer | 100 | 属性から入力できる項目 |
Date Modified | date | 2018-05-05T10:32:15Z | |
Date Added | date | 2018-05-05T10:30:07Z | |
Bit Rate | integer | 1009 | |
Sample Rate | integer | 44100 | |
Rating | integer | 60 | ☆による評価 ☆1つで20 |
Album Rating | integer | 60 | ☆による評価 ☆1つで20 |
Album Rating Computed | bool | true | |
Loved | bool | true | ♡による評価 Dislikedの反対 |
Disliked | bool | true | ♡による評価 Lovedの反対 |
Compilation | bool | true | CompilationのCheckbox |
Artwork Count | integer | 1 | Artworkの枚数 |
Persistent ID | string | AE6D45CB4E7D50E6 | |
Track Type | string | File | |
File Folder Count | integer | -1 | |
Library Folder Count | integer | -1 | |
Name | string | 曲名 | 属性から入力できる項目 |
Artist | string | アーティスト名 | 属性から入力できる項目 |
Album Artist | string | アルバムアーティスト名 | 属性から入力できる項目 |
Composer | string | 作曲者名 | 属性から入力できる項目 |
Album | string | アルバム名 | 属性から入力できる項目 |
Grouping | string | グループ名 | 属性から入力できる項目 |
Genre | string | ジャンル名 | 属性から入力できる項目 |
Kind | string | Apple Losslessオーディオファイル | |
Comments | string | コメント | 属性から入力できる項目 |
Sort Name | string | きょくめい | 読みがな |
Sort Album | string | あるばむめい | 読みがな |
Sort Artist | string | あーてぃすとめい | 読みがな |
Sort Album Artist | string | あるばむあーてぃすとめい | 読みがな |
Sort Composer | string | さっきょくしゃめい | 読みがな |
Location | string | file:///Users/aryzae/Desktop/ 01%20test%20name.m4a |
長いので改行している |
Mac AppでWindowからfileやdirectoryを選択してpathを取得するやり方
Mac Appの開発へ乗り出し
iTunesで曲を管理しているが、不便に感じていることがあるため、その辺の利便性をなんとかしたいと思い、Mac Appの開発を気ままに進めることにした。
ひとまずやりたいこと
- directoryを参照して、その配下にあるfile(subdirectory配下も含む)を列挙
コードと自分向けへの説明
下記のWindowを表示し、そこからdirectoryを選択させたい
- NSOpenPanelの
begin
メソッドで目的のWindowは表示できる - NSOpenPanelはPropetyによって、file選択、複数選択等を切り替えられる
@IBAction func openPanel(_ sender: NSButton) { let panel = NSOpenPanel() // fileを選択可能にするかどうか。defaultは、true panel.canChooseFiles = false // 複数選択可能にするかどうか。defaultは、false panel.allowsMultipleSelection = false // directoryを選択可能にするかどうか。defaultは、false panel.canChooseDirectories = true // 開始 panel.begin { response in // OK以外に`cancel`, `abort`, `stop`, `continue`があるが、`OK`, `cancel`以外は異常系 guard response == .OK else { return } // closure内でのみ選択したdirectoryのpathが取れる // また、panelの持つurlは、file protocol(file://)がついている self.readItems(url: panel.url) } }
NSOpenPanelで選択したdirectory配下のfileを列挙する
- 先ほどのコードでdirectoryのpathまでは取得できるようになったので、ファイルを列挙する
- FileManagerの
enumerator
メソッドで列挙可能 enumerator
のincludingPropertiesForKeys
で、列挙するfileの各種propertyも取捨できるのかと思ったが、後続のresourceValues
の時に指定したら取れているのでObj-C時代は必要だったが、今は不要?enumerator
のoptions
で、隠しファイルやsubdirectory配下も含めるかを指定可能enumerator
のclosure部分はerror handlerなので、必要に応じて書く
func readItems(url: URL?) { guard let url = url else { return } guard let directoryPath = URL(string: url.path) else { return } // includingPropertiesForKeysの意味あるのか? let enumerator = FileManager.default.enumerator(at: directoryPath, includingPropertiesForKeys: [.isDirectoryKey], options: [.skipsHiddenFiles, .skipsSubdirectoryDescendants]) { (url, error) -> Bool in // closuerは、errorハンドルのみ print(error) // trueならerrorでも継続、falseなら停止 return true } // 列挙 for element in enumerator! { guard let url = element as? URL else { return } print(url) let resourceValue = try! url.resourceValues(forKeys: [.isDirectoryKey, .nameKey, .isHiddenKey]) // forKeysで指定していないものは、nilになる print(resourceValue.isDirectory) print(resourceValue.name) print(resourceValue.isHidden) print(resourceValue.isPackage) print(resourceValue.localizedName) } }
03/18(日)に突発的に見知らぬ場所へ行きたくなり、宮城へ行った(後編)
キツネ村を出た後…
30分くらいあれば回りきれる園内を3時間程堪能したところで、駅へ戻るバスの時間になったので退園した。
これを逃すと500円の乗車賃で済むところが、タクシーを呼んで数倍のお金を払うことになるので…。
で、バスで行きの時に乗った場所、白石城跡へ戻ったところで12時過ぎということもあり、昼ご飯を食べれるところを探し始めた。新幹線で1駅、地方沿線でも数駅で仙台駅まで行けることもあり、とりあえず仙台に電車で向かいつつ、何を食べるかと次どこに行くかを検索した。
初 仙台
13時になるころに仙台駅に着いた。
お腹もかなり減っており、ガッツリ地方名産品食べるしかないなってことで、ありきたりながら牛タンを利休でいただいた。
仙台港も近いので、新鮮な魚類を寿司で食いたい気持ちもあったが、それは夜に食べることにした。
仙台うみの杜水族館
次に観光する場所は色々調べたけど、電車しか足がない自分には選択肢が結構限られていた。元来生き物が好きな節があったので、「仙台うみの杜水族館」の名前を見ても聞いたことなかったし、ピンと来なかったが、逆にどんな魚類が飼育されているか気になって向かった。
記憶違いかもしれないけど、2011/03/11の時に津波で生物がほぼ全滅した場所だったか?(調べたところ若干違い、「マリンピア松島水族館」というのがあったが、津波と老朽化の影響で2015年に閉館し、その後意志を継いで出来たのがこの水族館らしい。)
水族館で魚メインだけど他の生物も…
入ってすぐの場所にでかい水槽に多様の魚類が一緒くたに存在していてなかなか圧巻だった。
アジやらイカやら食卓で馴染みのある魚類からマンボウやらオオカミウオ、ダイオウグソクムシ等テーマがあるのかよくわからないけど、多くの生物がいた。
海水生物以外にも淡水生物でアリゲーターガーやピラルク、コイ、イワナとかもいたりする。そしてなぜかいるメガネカイマン。
魚介類、爬虫類以外だと、ツメナシカワウソや各種ペンギン、アメリカンビーバーもいる。
カワウソだとコツメカワウソが割とネットで見かけてもてはやされているが、ツメナシカワウソは数倍でかくて驚いた。そして飼育員のお姉さんが可愛かった。
自分が滞在時間中に、イルカのショー?をやっていたみたいだけど、個人的にイルカは興味の対象外+子連れの家族も多く空いて見れるチャンスと館内を巡っていた。
大きい方ではないが、展示されている種類が豊富だったこともあって、回りきる頃には夕方になっていた。
時間に余裕あれば、温泉でも浸かってから帰ることも考えていたが、突発的に遠征したため、この日が日曜日ということもあり翌日の仕事を考えて帰路につくことにした。
ずんだと寿司
夕飯は寿司の気分で完全に決まっていたので、行ければ漁港付近で寿司屋へと思っていた。しかし、水族館の最寄駅から帰り道と港は逆方向だったので、諦めた。
諦めたというより、港から仙台駅まで遠くないから、駅前でも鮮度良い寿司ネタは十分あるだろうと判断し、調べたところ"鮨勘"というお店が自分の懐事情に合いつつ美味いネタが食べれそうだったので、向かった。
時間も時間なだけに、寿司は持ち帰りで、あとは駅構内で売っていたずんだシェイクを携え新幹線へ乗り込んだ。
ずんだと寿司の食い合わせはちょっとアレだが、どちらも美味しかった。
特に寿司はシャリ少なめネタ厚めで満足度が高く、また食べたいくらいだ。
〆
突発的な日帰り旅行を行なったが、気ままで縛られない快適な旅だった。次どこいくか等のリサーチだけは時間かかるため、最低限食べ物と観光地、あとその場所の地理関係くらいはざっくり把握しておいたほうが、より効率的に移動や観光できたかもしれない。
まぁたまには非効率で無駄と思える時間を過ごすのも悪くはないとも思う。
次はGWあたりどこかいけたらなーと思う。観光客で混雑するから、GW明けとかでいけたら最高かもな。
03/18(日)に突発的に見知らぬ場所へ行きたくなり、宮城へ行った(前編)
ことの始まり
03/18(日)、数日前からふとした衝動でぶらりどこか適当な遠くへ行きたいという気持ちに駆られ、ノープラン気味にどこか行こうと思い立った。
で、どこ行こうか考えた結果、動物ではキツネと猛禽類が好きな自分としては、以前に掛川花鳥園でフクロウを堪能したので、国内唯一の蔵王キツネ村に行って見たいと思っていたので、行くことに決めた。残りは本当にノープランで朝1に出て新幹線に乗って宮城県の白石蔵王駅に向かった。
キツネ村入場
白石城跡から蔵王キツネ村まで試験的にバスが運行されており、その試験期間最終日だったのでタクシーで向かわずに済んだのは良かった。(タクシーだと3000〜4000円かかるらしい)
バスの乗る乗客は全部で12〜3人くらいだったが、うち10人くらいは中国人の観光客で、こういうややマイナーな行き先にも来るぐらいだからどこ行ってもいるんだろうなー。
20分かからないくらいだったか、バスで移動し、無事蔵王キツネ村に到着。こちらが入り口…
……
こちらが入り口。
意外に自家用車で来てたりタクシーで来てる人も多かった。蔵王といえばスキー場や樹氷でも有名だし、近くには温泉もあるので、そこからの流れで来やすいのもあるのかな。
入場料は大人1000円。まぁ良心的?
チケットを買うときに注意事項として受付のおばちゃんから説明を受ける。曰く「キツネが放たれてる檻に人間が入って行くことになる。近づいて来てもしゃがんだり、手を出さないでください。噛まれて怪我をします。また、しゃがんでスマホやカメラを構えると噛んで壊したりいたずらすることがあります。園内歩いていると後ろからキツネが近づいて来ることがあります。そのときは目を合わせてください。」のようなことを曖昧な記憶ながら言われた。
キツネとの戯れ
ざっくりおおきく分けて園内は3つのスペースがある。
- 檻の中に飼われていて、キツネの種類が明記されているエリア
- キツネが柵で囲われた広いスペースで放し飼いされており、餌やり(有料)ができるエリア
- キツネ以外のなぜかいるモルモットやうさぎ等のエリア
1. 檻の中に飼われていて、キツネの種類が明記されているエリア
2. キツネが柵で囲われた広いスペースで放し飼いされており、餌やり(有料)ができるエリア
日差しが気持ちいいぐらいで寝てるやつらばかりだったけど、耳だけこちらに向けてやや警戒してるやつもいたりで可愛かった。園内に100頭以上のキツネがいるらしく、所狭しとそこらじゅうにキツネがいて、時には喧嘩してる場面に遭遇する。
3. キツネ以外のなぜかいるモルモットやうさぎ等のエリア
割愛
1日に1〜2回キツネを抱っこできる時間が設けてあり、自分が滞在中もあったので、なかなか来ることないしせっかくだからと抱っこしてきた(600円)
蛍光色のは、雨合羽で抱っこしてる時に糞尿することがあるために着せられる。尿はとても臭いらしい。
一部のキツネは抱っこ中にジッとしてるのが嫌なのか、抱っこしている人間が嫌なのか暴れるのもいた。自分が抱っこしたのは、なんか顔からして悟ってる感じで微動だにしなかった。
キツネ村滞在の感想
狭い檻の中に閉じ込められるようにしてただ寝て過ごすキツネがいたり、放し飼いエリアで自由に過ごしているものの餌やりばで餌の取り合いによる喧嘩で激しくもみくちゃに暴れたりしていて、キツネ達から自然界にいるよりもストレスがかかっているように感じられた。
自然界のキツネを詳細に知ってるわけじゃないけど、金稼ぎの道具としてキツネがいいように扱われてるように見える部分があり、気持ちが引く印象を受ける部分もあった。
キツネの中には喧嘩で怪我をして首元がぱっくり裂けて肉が見えてるやつもいたり、頭に怪我の跡が残ってるやつもいた。
キツネはやっぱり好きだと思うけど、キツネ村に再度行きたいかと聞かれたら即答にしくいくらいには闇を感じた。
また、同じ観光客がキツネが喧嘩してるのを見てキャッキャいいながら笑ってたり、無邪気にかわいい〜って声を上げてるのにも寒気がした。
あぁ自宅でキツネ飼いたい…。 庭とかあるならホンドキツネでもアカキツネでもシロキツネでもいいし、室内ならフェネックとか飼いたい…でもフェネックお高い…。
いつかコキンメフクロウとフェネックを一緒に飼って共演させたいなぁ…(下手したらどっちかが捕食しそうで怖いからできない気もするけど)