2018年7月1日日曜日

UICollectionViewの並び替え(よくある編)

並び替えが出来るUICollectionViewに関する備忘録です。


まず、単純にUICollectionViewを表示するプロジェクトを作成しておきます。セルにラベルを用意して、番号を表示させているだけです。storyboardで、セルに色を付けておくと動作チェックがやりやすいかと思います。


ViewController.swift
ラベルに表示するデータを用意しています。
UICollectionViewDataSourceとUICollectionViewDelegateへの、selfのセットがありませんが、storyboard上で設定しておくと良いと思います。

右ドラッグで、クイっと。



ViewController+UICollectionViewDataSource.swift
セル上のラベルにインデックスを表示しています。


忘れがちですね、reuse idの設定



ViewController+UICollectionViewDelegate.swift
ラベルの表示だけなので、特に処理はありません。



CollectionViewCell.swift
セルにはラベルだけです。



これで実行すれば、とりあえずCollectionViewが表示されます。

とりあえず表示だけ


この状態のプロジェクトは次回にまた使うので、コミットをしておいてください。単純にコピーして取っておいてもかまいません。



♪ ♪ ♪



さて、ここから並べ替えが出来るように修正します。行うことは3つだけです。
  1. CollectionViewのセルの移動を可能にする。
  2. セルの移動処理を追加する。
  3. ロングタップのリスナーを登録する


ViewController+UICollectionViewDataSource.swift
collectionView(_ collectionView: UICollectionView, canMoveItemAt indexPath: IndexPath)でtrueを返して、セルの移動を可能にしています。

移動したときの挙動を、collectionView(_ collectionView: UICollectionView, moveItemAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath)に書きます。この例では元データの配列を移動しているだけです。



ViewController+LongPress.swift
CollectionViewの長押しのリスナーです。



ViewController.swift
あとは、ViewControllerのviewDidLoad()で、長押しのリスナーを登録します。
これで、セルの移動が可能になります。


めでたし、めでたし。で、「UICollectionViewの並び替え(iOS11編)」に続きます。


2018年6月15日金曜日

カモメに帰る日(そして苦言を呈するのだ)

「カモメに帰る日(反省した)」からのつづきです。


アメリカンスタンダード用のストリングガイドを取り付けたことを書きました。

なかなかかっこいいですな。

このストリングガイドは一般的な(このギターに元々付いていたものもそうですが)カモメ型のものより、弦に接する部分が少ないのでチューニングも狂いにくそうです。見た目も、ちょっとスマートでモダンな感じでもあります。

ただ、ちょっと、もの申したいこともあるのです。

以下、このストリングガイドを軽くディスるので、同じパーツが付いているギターをお持ちの方、ごめんなさい。読まないでください。


ご存じのように、通常ストリングガイドは弦の張力でほぼ真上に引っ張られます。それも結構な力で。

ストリングガイドを横から見るとこんな形です。

カモメ型のストリングガイド

カモメ型のストリングガイドは、弦を引っかけている部分、つまり上に引っ張られる部分が、ネジと同じ位置にあります。そのため力が、ネジを真っ直ぐ抜く方向にかかります。
この方向には木ネジは、結構頑張ります。

ところがこのストリングガイドは、弦を引っかけている部分が、ネジの斜め上にあります。しかも、ヘッドに接する面も狭いです。

アメスタのストリングガイド

木ネジ1本で固定されているだけなので、てこの原理でネジを支点にして、接地面をこじるように強い力がかかります。この木ネジは頭部の形状からも、ねじる方向には弱いです。

ストリングガイドは、地味ですが非常に重要なパーツです。演奏中にわずかでも緩めば、大きくチューニングが狂います。

オーバーに言うと、こう。

さらに、カモメ型でもそうですが、1個のストリングガイドで2本の弦を押さえています。それぞれの弦をチョーキングするたびに、左右にぐいぐい力がかかります。

ヘッドを上から見た感じ


使ってみた感じでは問題なさそうではあるのですが、どうしても不安感が残るのです。やはり、この短い木ネジには少々荷が重い気がします。思い切ってチョーキングをしたとたん、ストリングガイドが緩むなんてことが起きそうな。。。

んー、アメスタを使ってる人は気にならないのでしょうか?

でもまぁ、大丈夫か。

これ、もう少し接地面を長くして支点をずらすと良いと思うんです。

少しでいいんですよ。もうちょっとだけ。


さらに言えば、押さえる部分の面積が稼げるように、ネジの頭の形状をカバーするように、ワッシャーをかませられるだけのスペースが欲しいところです。木ネジの長さももう少し欲しいですね。
がっちりとね。


まぁ、付けちゃったものはしょうがないですが、気にしていても精神衛生上よくないので、カモメ型のストリングガイドに戻す日も近いかもしれません。


そして「カモメに帰る日(その後)」に続きます。


♪♪♪


こちらもどうぞ。
カモメに帰る日(考えたよ)
カモメに帰る日(ちょっと確認)
カモメに帰る日(反省した)
カモメに帰る日(その後)

2018年6月1日金曜日

カモメに帰る日(反省した)

「カモメに帰る日(ちょっと確認)」のつづきです。

テレキャスターの3弦のチューニング問題は、とりあえず解決しました。でも、ちょっと思うのです。

世間のテレ(ストラトも)はどうなの。困ってないの?

3弦4弦用のストリングガイドが付いているモデルも、あるにはありますが、通常は1弦2弦のみです。皆さんどうしてるんでしょうか。

と思いながら、もう一度ヘッドを眺めてハッと気付くわけです。ペグのポストに多めに巻けばいいのかと。そうすればナットのところの角度が稼げます。

あー、なんか聞いたことあるわ(笑)

僕のテレに元々付いていたペグは、GOTOHのものだったのですが、購入してすぐ、SPERZELに交換したのです。

SPERZELは弦をポストにほとんど巻かないことで安定したチューニングが得られるタイプです。ナットのところの角度を稼ぐためにポストの高さが6弦から1弦にかけて低くなるように作られてはいますが、3弦ではこのギターにとっては十分に低くなかったようです。

ん?ということは、1弦のペグと3弦のペグを交換するだけで解決したかも?

ま、いいか。

このヘッドの角度問題に関しては、伝統的な角度の付いたヘッドに利があります。もちろん良いことばかりではなくて、強度に少し難があって、ギターを倒したときなど、意外にあっさり折れちゃったりするらしいですけど。

レオ・フェンダーって人は、エンジニア気質で合理主義者だったそうです。旧来の楽器職人的発想とは違った角度から、革新的なギター、ベースを作り続けました。その彼はFenderのあともMusic Man、G&Lと、ヘッドのデザインは基本的に角度のないもので貫きました(もちろん例外はいくつもありますけど)。

この角度問題を抱えたデザインを採用し続けたレオ氏の判断は、一見すると合理的ではないようですが、強度はもちろん、製造工程の簡便さや歩留まり、机上での作業のしやすさなどを優先したのしょうね。

ただ、もしそうだとしても、ストリングガイドが2個付いたモデルがほとんどないのは、今ひとつ納得できないところでもあります。70年代にいくつかあったようですが、その頃には、レオ氏はもうフェンダー社にはいなかったですしね。

単に人気がないだけですか。そうですか。

今回はここまで。

「カモメに帰る日(そして苦言を呈するのだ)」に続きます。


♪♪♪


こちらもどうぞ。
カモメに帰る日(考えたよ)
カモメに帰る日(ちょっと確認)
カモメに帰る日(そして苦言を呈するのだ)
カモメに帰る日(その後)

2018年5月15日火曜日

Certificate Expires(拝啓、1年後の君へ)

毎度まいど、「どうやるんだっけ?」な事になるアレの備忘録です。


いつも忘れた頃にやってくる、'Action Needed: Mac Development Certificate Expires in 30 Days'のメールです。1年おきという、いい感じに忘れてるインターバルが涙をさそいます。

数年前、iOS開発者にMac開発者が付加されました。以前は別々に開発者登録しないといけなかったのですが、まぁ、お得な感じがしないでもないですね。Mac用アプリは作ってないですし、予定もないので、放置するという選択肢もありますが(笑)、ま、ちゃんとしておきましょう。

今回はMac Developmentですが、iOS Distributionとかでも同じだと思います。

※2018/08/01追記
iOS Distributionの方は、「Certificate Expires(拝啓、1年後の君へ) iOS Distribution編」に書きました。同じなんだけどさ(笑)。
※2021/10/02追記
証明書の期限切れを知らせてくれるメールが日本語になりましたね。
あと、Apple Distribution・Apple Developmentというのが出来ているのですが、これ、iOSとMacが統合されるのでしょうか。いずれにせよ、「更新しろよ」と連絡が来たらそれぞれ言われたとおりに更新しておけばいいと思います。

また君か。

さて、やることは以下の3つです。
  1. キーチェーンアクセスの証明書アシスタントで、証明書要求(Certificate Signing Request(CSR))ファイルの作成する。
  2. Apple Developerのサイトで、証明書(.cer)ファイルの作成する。
  3. 証明書を、キーチェーンアクセスに登録する。
※ 1.は毎回作成する必要はない(はず)です。次回のために大切に取っておくと良いと思います。もし「もう作ってあるよ」という場合は、2.-①までとばしてください。



では、「1. キーチェーンアクセスの証明書アシスタントでの証明書要求の作成」からです。

1.-①  キーチェーンアクセスを開いて、メニューの[キーチェーンアクセス]→[証明書アシスタント]→[認証局に証明書を要求]を選択します。


1.-②  証明書アシスタントが開くので、以下のように入力します。

  • [ユーザーのメールアドレス]に、メールアドレス
  • [通称]には、秘密鍵の名前
  • [CAのメールアドレス]は、空白
  • [要求の処理]は「ディスクに保存」を選択

※[ユーザーのメールアドレス]は、「そうでないといけない」というわけではないのかもしれませんが(自信なし)、開発者登録しているメールアドレス(Apple IDですね)が無難です。それ以外のアドレスを入力する積極的な理由はないですしね。

※[通称]に入力する「秘密鍵の名前」ってなに?、となりますが、Appleの例では、John Doe Dev Keyとなってます。つまり自分で区別がつくなら何でもいいので、ローマ字で名前を入れておけば良いんじゃないでしょうか。Taro Yamada Dev Keyとか。

Appleよ、「通称」より「鍵の名称」とかの方が親切なのでは?


1.-③  [続ける]を押すと、証明書要求ファイル(CertificateSigningRequest.certSigningRequest)が作成されるので、適当な場所に保存します。

[完了]で終わり




次は「2. Apple Developerのサイトで、証明書(.cer)の作成」です。

2.-①  Apple Developerのサイト(URLはメールにもあります)にログインして、[Certificates, Identifiers & Profiles]を開きます。


2.-②  今回はMac Developmentなので、"macOS"を選んで、[Certificates]を開きます。もうすぐ期限が切れる証明書が見つかると思います。
あー、6月11日に期限が切れますね。

2.-③  右上に追加ボタン(「+」)があるので押すと、"Add Mac Certificate"が開きます。[Mac Development]を選択して、[Continue]を押します。

2.-④  証明書要求(Certificate Signing Request(CSR))ファイルの作り方が説明されています。そのまま[Continue]を押します。
上記1.で作成済みですね。

2.-⑤  上記1.で作った、証明書要求(Certificate Signing Request(CSR))のアップロードを行います。
[Choose File]を押して、
1.で作った証明書要求を選択して、
[Continue]を押せば、アップロードされます。

2.-⑥  証明書要求(Certificate Signing Request(CSR))ファイルがアップロードされると、即座に証明書ファイル(mac_development.cer)が作成されますので、ダウンロードします。
証明書ファイルをダウンロードしたら、[Done]で終了。




最後は「3. 証明書のキーチェーンアクセスへの登録」です。

3.-①  キーチェーンアクセスを開いて、メニューの[ファイル]→[読み込む]を選択します。
実はここが「つまずきポイント」だったりします。

3.-②  上記2.-⑥でダウンロードした証明書ファイル(mac_development.cer)を選んで、[開く]を押します。

3.-③  無事、キーチェーンアクセスに証明書が登録されました。



補足)
3.の「証明書のキーチェーンアクセスへの登録」ですが、以前は2.-⑥でダウンロードした証明書ファイルをダブルクリックするだけで、キーチェーンに登録できたのですが、今回は上記のように、キーチェーンアクセスのメニューの[ファイル]→[読み込む]じゃないと登録できませんでした。macOSのセキュリティが厳しくなったからでしょうか。

ちなみに、証明書(.cer)ファイルをダブルクリックしたときに表示されたエラーダイアログがこれです。
おいどんは、意味わかんなくて泣いたとです。


1年後のオレよ、ちゃんと書いといたからなぁー!


♪♪♪


こちらもどうぞ。

2018年5月1日火曜日

カモメに帰る日(ちょっと確認)

「カモメに帰る日(考えたよ)」のつづきです。

3弦のピッチがちゃんと合わないのは、弦が十分な力でナットに押しつけられていないのが原因じゃないか?というところまででした。

「じゃ、3弦にもストリングガイドを付ければ解決だね」となる前に、ちょっと確認してみます。なにしろヘッドにネジ穴を開けることになりますから、付けてみたけどやっぱりだめだったね、では悲しいですから。

そこで、、、こう。

2弦の所に引っかけてみました。

写真ではちょっとわかりにくいですが、3弦を強引に、ストリングガイドの2弦のところに引っかけてみました。斜め下に引っ張ることになりますが、ナットに押しつける力は、3弦にストリングガイドを付けた状態に近くなります。

この状態でオクターブチューニングをあわせると、、、ばっちりです。

それならば!

というわけで、付けましたよストリングガイド。サウンドハウスで税込み842円。

安心?の純正パーツ

アメリカンスタンダード用のものらしいです。ネジ穴に加えてもう一つ回転防止用の穴が必要ですが、2個セットなのも好都合です。

取り付けはリペアショップにお願いしました。

工賃は5,400円(税込み)でした。

これでチューニングがちゃんと合うようになりました。めでたし、めでたし、なのですが反省点もあります。

今回はここまで。

「カモメに帰る日(反省した)」に続きます。


♪♪♪


こちらもどうぞ。
カモメに帰る日(考えたよ)
カモメに帰る日(反省した)
カモメに帰る日(そして苦言を呈するのだ)
カモメに帰る日(その後)

2018年4月15日日曜日

カモメに帰る日(考えたよ)

唐突ではありますが、僕のテレキャスターの3弦がどうもよろしくないのです。

オクターブチューニングをきっちり合わせても、ちゃんとピッチが合わないのです。ひょっとしてフレット音痴?と思ったりもするのですが、他の弦は大丈夫ですし、新品で購入してからほとんど弾いてないのでフレットも痛んでません。

まぁ、そんなものかなぁ、と思いながら「そこそこな感じ」でチューニングしていたのですが、チューナーアプリを作ってる身としては、

「それじゃダメじゃん(©春風亭昇太)」

なわけです。そこで、この音痴な3弦についてちょっと考えたので、それを。

症状としては、
  • オクターブチューニングをきっちり合わせる。
  • 当然開放弦はあっている。
  • でも、12フレット以外(例えば5フレットとか7フレット)を押さえると、ちょっと高い。

ここから考えられるのは、開放弦が本来のピッチより低くなっている、つまり開放弦の弦長が長いってことなのでは?となるのです。

そうすると、犯人はヤス原因はナットにあるということになりそうです。

文章で書くとわかりにくいですが、図にするとこうです。



ナットは開放弦の支点になりますが、正確にはナットの指板側の端(いわゆる0フレット)が支点にならないといけません。でも、支点がわずかにナットの内側にずれていたとしたらどうでしょうか。振動している弦が、ナットの溝の中で踊っている感じです。

これで1フレットの幅だけ正確な幅より少し広いという状態ができます。そんなギターは、たとえオクターブチューニングをしっかりあわせても、開放弦と12フレットを押さえた時にだけ正確な音程になるだけで、他のフレットを押さえたときには少しずつ音が外れてしまいます。

まさに上で示した症状そのものです。

では、なぜ弦の支点がナットの中にずれてしまうのでしょうか。

理由はいくつか考えられます。
  1. ナットの溝が広すぎる
  2. ナットの溝の角度が甘い
  3. ナットの溝の形状が悪い
  4. 弦をナットに押しつける力が弱い
  5. ビグスビーの呪い

1のナットの溝の幅は、そもそも弦に対して少し余裕を持たせて切ってあるものですし、支点のためにキツキツにするものではありません。そんなことをしたら、弦のゲージを変更するたびに、ナットを交換しなければなりません。

では、2はどうでしょうか。角度①がよほど浅いか逆になってない限りは問題なさそうです。もちろん、本来なら角度②に合わせて、きっちり切られている必要がありますけどね。


次に3ですが、このギターは買ってからほとんど弾いていないので、ナットはほぼ新品です。仮にフェンダーの仕事が多少の雑だったとしても、そんなにひどくはないでしょう。

ただ、これが原因だとすると、ちょっとやっかいです。溝の切り直しが必要ですし、その結果弦高が足りなくなるようなことになれば、ナットの交換ということになります。

極端に書くとこう。


そして4です。

角度②が浅いと、弦をナットに押さえつける力が弱いので、弦が滑ってナット上で振動してしまいます。いくら角度①が精密に切られていても効果半減です。さらにナットの溝の形状が少しでも悪ければ、大きく影響がでます。

逆に言えば、弦を押さえつける力がある程度強ければ、多少ナットの溝の角度や形が悪くても何とかなるといえます。

まさに、力は正義(笑)

この問題はギブソン系の(というか普通の)ギターのようにヘッドに角度が付いているものでは起きにくいですが、フェンダー系のヘッドで、特にストリングガイドの付いていない3弦、4弦で起きやすいと思います。

そこで、3弦(4弦もですが)にもストリングガイドを付けて、力業で解決できるのではないかというわけです。この仮説が正しいかどうか確かめようと、、、

今回はここまで。


あ、ちなみに5ですが、このテレキャスターにはあのアームユニットは付けてないので大丈夫です(笑)。

2018年4月1日日曜日

使ってみた(App Extension編) おまけ

「使ってみた(App Extension編) その5」からのつづきです。AppExtensionの話題からどんどん離れていきますが、今回はおまけです。


繰り返しになりますが、AppExtensionと収容アプリケーションは別アプリ扱いです。

そのため、実際のユースケースでは、AppExtensionを使った後ですぐに収容アプリケーションを起動するとは限りません。AppExtensionでのコンテンツの保存を繰り返した後に、収容アプリケーションを起動するというケースも普通にあるでしょう。

そこで、もうひと工夫して、AppExtensionでUserDefaultに保存するときに、Contents型の配列でため込んで、収容アプリケーションで取得するときにまとめて取得するようにします。

好都合なことに、Codableの配列はCodableなのでそのままエンコード、デコードできます。

UserDefaultは上書き保存ですから、AppExtensionでデータを保存するときには、いったんデータを取得してから、その配列に新たにデータを追加してから保存し直します。

これでAppExtensionでどんどん追加保存できます。
    /// コンテンツをApp Groupのユーザーデフォルトに保存
    ///
    /// - Parameter content:
    private func saveContent(content: String) {
        guard let userDefaults = UserDefaults.init(suiteName: "group.jp.blowbend.ios.test.AwesomeApp") else {
            print("userdefault: app group suite name is nil")
            return
        }
        
        //保存済みのデータの取得
        var contents: [Contents] = []
        if let object = userDefaults.object(forKey: "user default key content") {
            if let data: Data = object as? Data {
                do {
                    contents = try JSONDecoder().decode([Contents].self, from: data)
                } catch {
                    print("ActionViewController: JSONDecoder decode error")
                }
            }
        }
        
        let c = Contents(key: 123, text: content, date: Date())
        contents.append(c) //新たにデータを追加
        do {
            let data = try JSONEncoder().encode(contents) //Data型に変換
            userDefaults.set(data, forKey: "user default key content")
            userDefaults.synchronize()
        } catch {
            print("userdefault: contents encode error!!")
        }
    }

収容アプリケーションでデータを取得するときは、単純に配列で受け取ります。貯まっていたデータを受け取ったら、removeObjectでデータを削除して空にします。
    /// App Groupのユーザーデフォルトからコンテンツを取得
    private func getContentFromAppGroup() {
        guard let userDefaults = UserDefaults.init(suiteName: "group.jp.blowbend.ios.test.AwesomeApp") else {
            print("userdefault: app group suite name is nil")
            return
        }
        guard let content = userDefaults.object(forKey: "user default key content") ?? nil else {
            print("userdefault: no content")
            return
        }
        guard let data = content as? Data else {
            print("userdefault: no data")
            return
        }
        
        do {
            let contents = try JSONDecoder().decode([Contents].self, from: data) //Content型の配列で取得
            for c in contents {
                print("c.key =\(c.key)")
                print("c.text=\(c.text)")
                print("c.date=\(c.date)")
            }
        } catch {
            print("userdefault: JSONDecoder decode error")
        }

        userDefaults.removeObject(forKey: "user default key content") //すべてのデータの削除
    }


どうでしょうか。これでAppExtensionの呼び出しごとに、(実は動いていない)収容アプリケーションにデータを送っているかのように見せられますね。このあたりは、その処理に合わせて色々工夫のしどころかもしれません。

以上で、使ってみた(App Extension編)は終わりです。おつかれさまでした。


こんな風にAppExtensionを使ったアプリをリリースしました。よろしくね。


「おまけのオマケ」
App Extensionを含むアプリをiTunes Storeにリリースするときは、ビルド番号を収容アプリケーションとApp Extensionとで揃える必要があります。

もし違うままアップロードすると、

WARNING ITMS-90473: "CFBundleVersion Mismatch. The CFBundleVersion value '2' of extension 'AwsomeApp.app/PlugIns/AwsomeAppShare.appex' does not match the CFBundleVersion value '1' of its containing iOS application 'AwsomeApp.app'."

というワーニングが出ます。ワーニングなので実害はないのかもしれませんが、まぁ、不用なトラブルは避けた方がいいですよね。お気を付けください。


♪♪♪


こちらもどうぞ。
使ってみた(App Extension編) その1
使ってみた(App Extension編) その2
使ってみた(App Extension編) その3
使ってみた(App Extension編) その4
使ってみた(App Extension編) その5

iOS 11 Programming
  • 著者:堤 修一,吉田 悠一,池田 翔,坂田 晃一,加藤 尋樹,川邉 雄介,岸川克己,所 友太,永野 哲久,加藤 寛人,
  • 発行日:2017年11月16日
  • 対応フォーマット:製本版,PDF
  • PEAKSで購入する