2016年10月4日火曜日

Q. ATS を Debug ビルドでだけ無効にしたいのですが...

A. こちらの内容に従えば一発です。

要するにBuild Phaseにビルドスクリプトを追加してそこでPlistBuddyを使って値を書き換えましょうと言う作戦です。

もうちょっとマシな解説

普段、Info.plistの設定内容をConfiguration毎に書き換えたい場合は、たいていよくやるのがxcconfigファイルを以下のように用意して、
APP_BUNDLE_NAME = MyApp_Dev
でもってInfo.plistに対して
Bundle Display Name = ${APP_BUNDLE_NAME}
こんな風に書いておけばビルド時に自動的にXcodeが環境変数による置換処理を行ってくれる、というのを使うのですが、まいったことにATSの設定を司るNSAllowArbitraryLoadsはString値ではなくBool値でして、このInfo.plistに対するXcodeの環境変数置換処理はString値(と、確かNumber値)にしか使えないというオチがあります。仕方がないので最初に説明した方法が最善になるかと思います。Info.plistファイルをConfiguration毎に用意する方法もありますが、大概そっちのほうが設定のメンテナンスが面倒になるのでオススメしません。

2016年10月3日月曜日

ATS の AVFoundationに対する 例外条項の注意点

2016/10/03段階でのATSを有効にする際の覚書です。基本的には全てTLS 1.2以上をサポートするhttpsにしてしまえばOKですが、例外条項としてAVFoundationのStreamについてはhttpでもよいと例外条項が定められています。

https://developer.apple.com/videos/play/wwdc2016/706/?time=324

これについては設定不要で自動的に適用されるようにWWDCのビデオ上では見えますが、実は落とし穴があり、この例外条項はiOS 10以降でのみしか適用されません。iOS 9については実はAVFoundationのStreamについてATSが完全に適用されているようで、httpの動画をStreamingしようとしても失敗してしまうので注意が必要です。

2016/10/03 16:45 追記
こちらXcode 7.3.1でビルドしたバイナリにて調査した内容ですので、SDKのバージョンが異なるXcode 8.0以降でビルドしたバイナリであればiOS 9.x系でもAVFoundationのStreamについてATSの例外条項が適用されてhttpで通信できるようになるかもしれません。ただ紹介した参照元のWWDCのビデオを見ても分かる通り、基本は例外を考えず全てhttps化するのが良いとされているため、ビデオストリームについても可能であれば全てhttps化するほうがトラブルがないかと思います。

2016年9月11日日曜日

Parse.com が潰れたので新しい mBaaS を探す旅に出た

定番のmBaaSとして人気だったParse.comが終わってしまうことが確定してしまった2016/09/11現在、次はどのようなmBaaSを選ぶのが良いのか調べてみました。なおどのプロダクトも全然試せていないので実戦での詳細な評価についてはできかねます。むしろこれを読んだ皆さんに果敢にトライしていただきたい!\(^o^)/

Niftyクラウド mobile backend


http://mb.cloud.nifty.com

  • 国内だとここ
  • ちょっと前にひとりぼっち惑星がここ使ってるといって有名になった
  • 正直機能的にはダメだと思ってる
    • その話題になったブログ記事の内容が、データストアにトランザクションに相当する処理を新機能として導入しました、とかDBキーによる高速ルックアップを実装しました、とかそういう次元の、あまりにも最初から存在して当然と思われる機能を新規実装として誇っているような内容だったため
    • 逆に言えば今後もこの調子で継続的に改善してくれるかも
  • Niftyが社命賭けてるっぽいしそう簡単には潰さないと信じてる

Google Firebase


https://firebase.google.com

  • なんといってもGoogle様ブランドがある
  • Analyticsが非常に素晴らしい、GAをリプレイスして、Analyticsのためだけに導入する価値がある
  • 一方でiOS/Android/Webプラットフォーム全てで同一の概念を利用できるように、各プラットフォーム独自の箇所をラップして激しく潰しているように見える
    • 特にFCMと呼ばれるPush通知に相当する箇所についてはAPNSが元の影も形も見えないぐらい激しくラップされていて操作できないため、例えば今の時期だとiOS 10向けのUserNotifications.frameworkに対応させるのが実質不可能とかそういうデメリットがある
    • iOS側が割を食いそうな不安はある
    • とはいえ調べてみたところiOS 9からのUniversal LinkはApple仕様に従ってきちんと対応するようになっていて、Firebase側は全く無視する気はなく、対応が遅れるのを許容できるのであれば大丈夫そう
  • Googleだし気合入れてるみたいだしそう簡単には潰れない・・・はず・・・
    • とはいえ最近のGoogleは不採算プロダクトを平然と潰すので油断ならない

backendless


https://backendless.com

  • パッと見一番Parse.comっぽい
  • トップページからして「Migrating from Parse? Welcome to Backendless!」だし
  • 一番Parseっぽくて下手にラップするようなことをしておらず、かつ必要な物は全部あるので最も個人的には好感
    • Firebaseみたいに激しくラップされすぎる構造は、例えるならRuby on RailsやPython Djangoのような感覚があってどうも個人的には好きになれない
  • ただしParseの二の舞いのように潰れる可能性もまた否定出来ない


まとめ

どこも潰れるリスクがワンチャンありそうですね(´・_・`)
ご利用はご計画的に\(^o^)/

iOSのフォントのお話

最近フォント周りについて深く掘り下げる機会がありましたので、その際のメモを残しておこうと思います。かなり読む人置いてけぼりな中身になってますが、フォントを詳しく触り始めるとなるほどーとためになる(と思う)のでどうかご了承ください(´・_・`)

UIFontのプロパティについて

UIFontにはフォントに関する数値を表すプロパティが存在します。いろいろありますが、もっとも重要なのは以下に列挙するプロパティです。

  • pointSize
  • lineHeight
  • ascender
  • descender
  • leading
  • capHeight

以下の画像を見ると非常にわかりやすいかと思います。


参照元: https://developer.apple.com/library/ios/documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/CustomTextProcessing/CustomTextProcessing.html および http://stackoverflow.com/a/35922853

これを踏まえて各プロパティを解説すると以下のとおりになります。
  • pointSize
    • フォントのサイズを表します。
    • ほとんどすべてのケースでpointSize = ascender + descenderとなり、すなわちpointSizeは上端と下端に空白を含まない純粋なフォントの高さだけを表す数値であると言っても良いと思います。
      • 上下に空白を作らない高さでフォントを描画したい場合はこの高さを使うと良い、と言い切って間違いないと思います、ごく一部の変なフォント以外。
  • lineHeight
    • フォントの上部末端(上端空白が存在する場合はそれも)から下部末端(line gapも存在するなら含む)までの完全な高さを表します。
    • 飾り文字などではないまっとうなフォントであれば、必ずこのlineHeightの中に文字の高さが収まるようになっています。
      • 一部飾り文字のあるフォントについてはfont leadingを使って下部末端のline gapを表現していることがあります。
    • pointSizeとの最も大きな違いは、上端と下端にline gapに相当する空白を持っています。特にシステムフォントで顕著にそれが見られます。詳しくは後述。
    • 実際にフォントが画面上にレンダリングされるときはこのlineHeightがすべての基準になっているケースが多いです。
  • ascender
    • 全てのアルファベットの文字の最大高さを表します。
    • この高さまで描画されるのはごく一部の文字だけで、殆どの文字はcapHeightまでの高さしか使いません。詳細はこの後のcapHeightを参照してください。
  • descender
    • アルファベットのBaselineより下に描画される文字、例えばj p q yなどの下付き部分の高さを表します。
    • 日本語の文字でこの領域に描画される文字は私が知っている限りでは存在しません。
    • UIFontが返す値は常にマイナスになるので気をつけてください。
    • CTFontが返す値は常にプラスです。
      • めんどくさいので常にfabs()を通すといいと思います。
  • leading
    • Baselineからフォントの下部末端(line gapを含む)までの高さを表します。
    • 上記の図ですとline gapの部分だけがleadingとなっていますがヒラギノフォントで試した限りは誤りです。Baselineから下全てが対象になっているようです。
    • lineHeightに含まれている下部末端のline gapとは「全く別の値が付与されていることがあります」。
      • 例えば飾り文字のあるフォントについて、lineHeightよりもフォントの描画が大きくなるぐらい下に飾りが伸びていたとしても、leadingの値はそこまで考慮して付与してあるので、usesFontLeadingのオプションを付与すると下の行にはみでなくなる、みたいなケースが存在します。
  • capHeight
    • アルファベットの大文字の最大高さを表します。
    • 日本語の文字は(特に漢字は)基本的にすべてcapHeightの高さに描画されます。
    • capHeightより上に描画されるのは、例えばÅ(Aウムラウト)のように修飾子が付いているアルファベットや、日本語だと濁点および【】隅付き括弧のような一部の文字が、capHeightよりも上に描画されます。
特に覚えておきたいのがleadingというプロパティの働きです。UIKit, TextKit, Core TextにusesFontLeadingというような名前のオプションが存在するケースが多々ありますが(例えばNSAttributedString.boundingRect(with:options:context:)のoptionsとかですね)、これは何かというと、
usesFontLeadingが指定されている場合、lineHeightの計算の際に常にUIFont.leadingの値が使用される。従って、もしattributed stringにparagraph styleを付与してlineSpacingに0を付与していたとしても、フォントにleadingの値が付与されていたら、それ以上に行の高さが低くならず必ず行間が開いてしまう。
というオプションになります。paragraph styleでlineSpacingやparagraphSpacingを0に指定しているにもかかわらずどうしても行間がゼロにならないとか、指定するより広がってしまうみたいな状況になった場合は、このfont leadingを疑ってみてください。

ちなみにiOS 8以上については以下のとおりです。

  • UILabelは常にfont leadingを使用しません。
  • UITextFieldは未調査ですがおそらく常にfont leadingを使用しません。
  • UITextViewはデフォルトfont leadingを使用しますが、UITextView.layoutManager.usesFontLeadingの値をfalseにすることで回避可能です。
  • その他のラベルパーツ(UIButton.titleLabelなど)については完全には調査できていませんが、UIButton.titleLabelに関してのみいうとiOS 9の地点ではfont leadingが常に「使用されてしまいます」。これはおそらくiOS 6以前のUILabelの挙動がそのまま残っているためではないかと思われます。同じUILabelクラスですが中身と挙動がUILabelと異なるため気をつけてください。このようなケースは他にもあると思われます。

iOSビルトインフォントの問題点

幾つかのiOSビルトインフォントについては、先述のUIFontのプロパティの値に疑問がある数値が設定されているケースが有るようです。具体的にご紹介します。

1. ヒラギノフォントの場合

ヒラギノフォント、すなわちヒラギノ角ゴシックW3/W6、それからヒラギノ明朝W3/W6については以下の様なフォントの設定の特徴があります。
  • leadingの値がきちっと付与されています。
  • 常にpointSize == lineHeightになります。
  • おそらくバグだと思うのですが、descenderの値が本来必要な量の半分しか設定されていません。そのためヒラギノフォントを明示的に付与したラベルにg, j, y, qなどの下付き部分があるアルファベット文字を描画すると下が途中で千切れてしまいます。
    • 対処法としてはfont leadingを使用するか、または自力でdescender分だけラベルの高さを高くするか、明示的に指定してヒラギノフォントなんて使うのをやめてシステムフォントを使用してください。

2. システムフォントの場合

次にシステムフォントはどうなっているのかというと、以下の様な特徴があります。
  • 常にleadingの値がゼロになります。従ってfont leadingを使うモードで描画しても使わないモードで描画しても全く同じ結果になります。
    • iOS 8はHelvetica Neue, iOS 9以上はSan Franciscoが採用されていますが、いずれのケースでも全く同様の設定になっています。
  • pointSizeよりlineHeightが高く、ちょうどその差分の分だけ自動的にline gapとして行間が開くような設定になっています。
    • 要するに簡単にいえば、font leadingを使わないで、かつattributed stringでlineSpacingやparagraphSpacingをゼロに設定したとしても、必ず行間がちょっとだけ空いてしまいます。まずやることはないと思いますが、正確に行間ゼロを作るのは著しく困難です。

UIFontのpointSizeについて

UIFont.pointSizeについて、みなさん普段から何気なしに17とか14とか値を指定されているかと思いますが、このpointSizeに指定する値の単位って気にされていますでしょうか?このフォントのpointSizeとはPostScriptポイントないしDTPポイントと呼ばれるものらしいです。一般的に1PostScriptポイント=1/72インチとされています。

ではこの単位はiOS上で使われている論理座標系のpt単位とは全く違うものなのかというと、どうやら大昔のMacintoshのころからの名残で、macOS/iOS上の論理座標系の1pt=1PostScriptポイントとなるように定められていて、これは現在に至るまで常に維持されているということらしいです。

要するに、UIFontのpointSize=iOS上での1ptと完全に一致します。このことはlineHeightが16のフォントを画面上にレンダリングすると論理単位16pt(2倍Retinaなら32pxになる)ことからも確認ができます。便利ですね。


UIFont.leadingのiOS 8以下での不具合

かいつまんで言うと、UIFont.leadingの値は、iOS 8以下のときに常にUIFont.lineHeightと同じ値を返します。これは"font leading"という単語が使われている文脈や文化圏によって意味が異なり、font leading = line heightとなる文化圏があったので誤用されてしまった、ということらしいです。しかしながら実際のiOSでは先述の通り「font leading = BaselineからフォントのLine gapを含む下端までの距離」と定義されていますから、このような値では困ります。

対処法として、iOS 8以下の場合はCTFontを使ってleadingの値を取得してください。こちらにコードを用意しました。
https://gist.github.com/akisute/3c3d162da73abd784525c9ed7859cda2

なお、iOS 9以上はこの問題は発生しません。iOS 8なんてそろそろサポート切れるんで忘れていいかもしれませんが、念のため。

まとめ

デザイナーさんにフォント周りで行間調整がおかしいぞーとかベースラインがずれてるぞーとか突っ込まれまくっていて必死こいて修正方法を調べている時に、こんな記事を見つけました。

https://www.raizlabs.com/dev/2015/08/advanced-ios-typography/

Stop Saying "No" to Designers.
このサイトには英字フォントをBaselineではなくcapHeightの位置で上揃えにするべく奮闘した一人の漢の話が書かれています。おお、海外にも私と同じ境遇の漢が居たのです。

我々もデザイナーにNOと言わないタイポグラフィを実現させたいですね\(^o^)/

2016年6月30日木曜日

Auto Layout と Manual Layout を混載させるときに役立つ UIView.translatesAutoresizingMaskIntoConstraints プロパティの話

Auto LayoutがiOS 6で導入されてはや4年、未だによく理解していなかった挙動に UIView.translatesAutoresizingMaskIntoConstraints があります。このプロパティは自分がプログラムコード上で生成したviewをAuto Layoutするときにfalseにする必要があるものということで皆様記憶されているかと思うのですが、具体的にこのプロパティは何をやっているのかが個人的に全く謎でした。それが今日一つ謎が解けましたのでここに共有させていただきたいと思います。

UIView.translatesAutoresizingMaskIntoConstraintsの値がtrueのときとfalseのときの違いについて以下に記載します(iOS 8以上で確認しています)。

  • trueのとき
    • 対象のviewのframe、すなわちx, y, width, heightの4つの要素をview.frame, view.bounds および view.center プロパティから直接操作することが可能になります。これはAuto Layoutが導入される以前のiOSの世界と同じ状態です。この挙動をAuto Layoutとマッチさせるため、対象のviewのx, y, width, heightの4要素を指定された値に固定するようなAuto Layout Constraintsが自動的にシステムによってviewに挿入されます。この自動的に挿入されるAuto Layout Constraintsのpriorityは常に1000 (Required)になります。
  • falseのとき
    • 対象のviewのframe、すなわちx, y, width, heightの4つの要素はすべてAuto Layoutエンジンが管理するようになり、view.frame, view.bounds および view.centerの値を直接書き換えても一切無視されるようになります。Auto Layout Constraintsが設定されていない場合、viewのframeはCGRect.zeroになります。

プロパティの名前にAutoresizing Maskとか入っているのでてっきりAutoresizingの仕組みに影響している用に見えますが、実際には全く関係ありません。その証拠にAutoresizingMaskの値をどのように変化させても勝手にAuto Layout Constraintsが挿入されてしまいます。このプロパティはあくまで当該viewのframeを自動的に操作するようなAuto Layout Constraintsを挿入するか否かを決めるフラグとして覚えると良いでしょう。

さてこの挙動を覚えると何が嬉しいかと申しますと、Auto Layoutと非Auto Layoutを混載させるときに非常に役立ちます。こうすることで、特定のviewだけをframe手動操作で設定し、他のviewはAuto Layoutに任せるというような荒業が自由自在に可能になります。

具体例を見てみましょう。例えば以下の様なニュースを表示する画面を作ってみようと思います。



ここでこのnewsを表示するviewのframeは複雑なアニメーションをさせたいなどの理由で外部からマニュアルで設定したいが、viewの中身はauto layoutに任せたいというようなケースがあるかと思います。

というわけで普通にAuto Layoutで作ってみましょう。
private func commonInitialize() {
        self.translatesAutoresizingMaskIntoConstraints = true
        self.backgroundColor = UIColor.white()
        
        self.imageView = UIView()
        self.imageView.translatesAutoresizingMaskIntoConstraints = false
        self.imageView.backgroundColor = UIColor.green()
        self.addSubview(self.imageView)
        
        self.titleLabel = UILabel()
        self.titleLabel.translatesAutoresizingMaskIntoConstraints = false
        self.titleLabel.text = "factorio alpha 0.13 has been released!"
        self.titleLabel.font = UIFont.preferredFont(forTextStyle: UIFontTextStyleTitle1)
        self.titleLabel.numberOfLines = 2
        self.addSubview(self.titleLabel)
        
        self.articleLabel = UILabel()
        self.articleLabel.translatesAutoresizingMaskIntoConstraints = false
        self.articleLabel.text = "In 0.13 we have the new multiplayer matching server and server browser. This will let you find games of people online join your friends and other stuff. Server games are published to the server and clients can browse existing games. The first thing you will notice is the new multiplayer menu. When you click on 'Browse Public games' you will be asked to log in to your factorio account."
        self.articleLabel.font = UIFont.preferredFont(forTextStyle: UIFontTextStyleBody)
        self.articleLabel.numberOfLines = 0
        self.addSubview(self.articleLabel)
        
        let views: [String: AnyObject] = ["imageView": self.imageView,
                                          "titleLabel": self.titleLabel,
                                          "articleLabel": self.articleLabel]
        
        self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[imageView]|", options: [], metrics: nil, views: views))
        self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-10-[titleLabel]-10-|", options: [], metrics: nil, views: views))
        self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-10-[articleLabel]-10-|", options: [], metrics: nil, views: views))
        self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[imageView]-10-[titleLabel]-10-[articleLabel]|", options: [], metrics: nil, views: views))
        self.imageView.addConstraint(NSLayoutConstraint.init(item: self.imageView, attribute: .height, relatedBy: .equal, toItem: self.imageView, attribute: .width, multiplier: 0.66, constant: 0))
    }


しかしながらこのコードはAuto Layout Warningが発生してしまいます。

2016-06-30 23:24:12.050906 AutoLayout[1725:80607] [LayoutConstraints] Unable to simultaneously satisfy constraints.
 Probably at least one of the constraints in the following list is one you don't want. 
 Try this: 
  (1) look at each constraint and try to figure out which you don't expect; 
  (2) find the code that added the unwanted constraint or constraints and fix it. 
 (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) 
(
    "NSAutoresizingMaskLayoutConstraint:0x7fd60ae1db90 h=--& v=--& AutoLayout.Example2View:0x7fd60ad35b70.width ==   (active)",
    "NSLayoutConstraint:0x7fd60ac360a0 H:|-(10)-[UILabel:0x7fd60ad3c6b0'factorio alpha 0.13 has b...']   (active, names: '|':AutoLayout.Example2View:0x7fd60ad35b70 )",
    "NSLayoutConstraint:0x7fd60ac36380 H:[UILabel:0x7fd60ad3c6b0'factorio alpha 0.13 has b...']-(10)-|   (active, names: '|':AutoLayout.Example2View:0x7fd60ad35b70 )"
)

これは先程のUIView.translatesAutoresizingMaskIntoConstraintsについての説明を元にすると以下のように解釈できます。

  1. UIView.translatesAutoresizingMaskIntoConstraintsがtrueに設定されていることにより、このviewにはwidth=frame.size.widthになるようなAuto Layout Constraintsが自動的に設定されている。
  2. このviewにはさらに "H:|[imageView]|"となるようなAuto Layout Constraintsが設定されている。これはimageViewを横幅いっぱいに表示するため。
  3. しかしながらこのような設定を行うと、imageViewが親となるviewの横幅を自分の横幅に合わせて引っ張ろうとするConstraintsが定義されてしまうので、1. で自動的に設定されたConstraintsと衝突してしまう。
  4. 結果としてwarningが発生する。
これを回避してやるにはいくつか方法があります。

  1. "H:|[imageView]-(0@999)-|"のように設定することで、右側ないし下側のpriorityを999に下げる。こうすることによってUIView.translatesAutoresizingMaskIntoConstraintsによって設定されるConstraintsのpriorityが勝つためワーニングは発生しなくなる。
  2. 両側を引っ張るようにvisual formatを使って設定するのをやめて、view.x=imageView.x, view.width=imageView.widthとなるようにConstraintsを付与する。
例えば2. のケースはiOS 9以降であればNSLayoutAnchorを使って簡単に設定ができます。

self.imageView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
self.imageView.widthAnchor.constraint(equalTo: self.widthAnchor, multiplier: 1.0).isActive = true

これでAuto LayoutとManual Layoutをより自由自在に混載させることが可能になると思います。

2016年6月19日日曜日

ゼロから始めるマインクラフトのサーバー構築の話

突然なのですが、最近いまさらながらマインクラフトに大ハマリしておりまして。きっかけは友人のマルチプレイサーバーでプレイしたことだったのですが、やっぱり皆で遊ぶゲームは面白いなと再確認している次第です。マインクラフトはリリース直後、βが取れたぐらいに遊んで面倒でやめてしまったのですが、近頃はFeed The Beastと呼ばれるオールインワンのランチャーアプリが登場しており、こいつがMODの導入や管理も全て一発でやってくれるため面倒やストレスが一切なく楽しめます。

で、しばらく遊んでいたのですが、友人が他のゲームにハマってしまったためマインクラフトのサーバーを立てなくなってしまいました。そこで私のほうで自分でマインクラフトのサーバーを立ててやろうと思い立ちまして早速今週末チャレンジしてみました。

ちなみに私インフラに関しては大の苦手で、サーバーをゼロから構築するのは初めてだったりします。大昔新卒の頃にSIerの仕事でちょっと触ったりとか、その後の仕事でちょっと触ったりとかした程度。アプリケーションなら分かるんですけど(´・_・`)

前置きはこのぐらいにして早速やってみましょう。

ホスティングサービスを選定

パッと思いつくところだとさくらVPSとAWSが有名ですが、今回は友人のおすすめでConoHaというVPSホスティングサービスを選んでみました。ほとんどさくらVPSと大差ないように見えたのですが、ConoHaのほうがさくらVPSと違い初期費用がかからないらしいです。新しいもの好きですしせっかくなのでConoHaを選択。

サーバーのスペック等は以下のようにしました。CentOS 7.2に3コア2GBメモリで月1750円。マインクラフトのサーバであればこのぐらいの性能で大丈夫なはず。


とりあえずサーバーを起動してsshまで

構築したらすぐにインスタンスが起動します。ConoHaでは自動的に固定Public IPが1インスタンスに割り当てられるようで、この点固定IPを用意したりするのが何かと面倒なAWSに比べて楽でした。管理画面もすっきりまとまっていて使いやすく好印象です。キーペアもその場で同時にすぐ作成してくれて手間がかかりません。

生成したキーペアをローカルの ./ssh 以下に保存して ./ssh/config を適当に設定してログイン。root@を付け忘れてssh接続要求に失敗するみたいなよくあるお約束のミスをしましたが、特に問題なくログインできました。

ログインに成功したのを確認してから手持ちのドメイン (akisute.com) のサブドメインを用意してDNSを設定してやります。疎通して問題なし。

nginxを立てる

サーバーの情報などをウェブに公開したいので、nginxを利用してstatic htmlファイルをホスティングできるようにします。nginxのCentOS 7.2に対するインストール自体はこちらのページに従えばすぐにできます。
http://nginx.org/en/linux_packages.html
後は以下のビギナーズガイドに従って設定を行えば良いのですが、基本的には最初から全て必要そうな設定は用意されているので、/usr/share/nginx/html以下のindex.htmlを適当に編集してやるだけでオッケーです。
http://nginx.org/en/docs/beginners_guide.html

firewalldを設定する

しかしながらnginxを立ち上げただけでは外からアクセスしてもつながりません。これはCentOS(に限らないですが、ほとんどのLinuxのディストリビューションについて)は何らかのファイアウォールがデフォルトで入っているためです。一般的にはiptablesが使用されているのですが、CentOS 7ではiptablesではなくfirewalldというやつが使われているらしいので、そちらを設定することにしました。
http://urashita.com/archives/963
http://www.unix-power.net/centos7/firewalld.html

httpサービスをpublicゾーンの設定に追加するだけで簡単に外からアクセスできるようになります。iptablesより簡単でいいですね。

Javaをインストールする

マインクラフトはJavaで動作するので最新版のJavaが必要です。Javaには大きくOpenJDKとOracle Javaがありますが、個人的にはOracle Javaのほうが速そうなのでそちらを使うことにしました。以下のページで紹介されているとおりにすれば簡単にインストールできるかと思います。
https://www.digitalocean.com/community/tutorials/how-to-install-java-on-centos-and-fedora

minecraft-serverを立てる

いよいよ本題のminecraft-serverです。これについてはFTBのmodpackであればFTBのクライアントからDownload Serverボタンを押すだけでzip形式で最初から用意されたサーバーセットアップ一式がダウンロードできますので、ダウンロードURLをコピーしておいてサーバー側からwgetして取得しunzipするだけで準備完了です。
http://www.feed-the-beast.com/servers

unzipして展開した中身のServerStart.batをServerStart.shにして中身を適当に書き換えてやり(主にJVMの起動オプションからヒープに割り当てる量を調整するなど)実行すれば簡単にサーバが立ち上がります。ただし普通に立ち上げるとシェルを専有されてしまうので、screenなど経由でServerStart.shを実行するようにすればいいでしょう。
http://www.minecraftforum.net/forums/support/server-support/server-administration/1897274-how-to-use-screen-on-your-linux-minecraft-server

あとはサーバーコマンドで自分をopにでも追加しておけば良いと思います。起動したサーバーのコマンドラインから /op 自分の名前 とコマンドを実行すればopを付与できます。その他必要に応じてminecraft-serverの設定ファイルを操作したりgameruleを調整すれば良いと思います。

最後に先ほど設定したfirewalldにminecraftサービスを追加して、外からアクセスできるようにすればおしまいです。minecraftはhttpと違ってデフォルトでサービスが用意されていないので、自分でサービスを追加する必要があります。サービスの追加は/etc/firewalld/servicesにxml設定ファイルを追加すればよいです。サンプル代わりにデフォルトのサービスのxml設定ファイルが/usr/lib/firewalld/services以下に配置されているので適当なものをコピーして改造して使えばよいです。minecraftはtcp/udpの25565がデフォルトポートなのでここを開くように設定してfirewalldを再起動すれば外から繋がるようになるかと思います。

その他の設定

ログローテーションを設定しておかないとディスクがログで溢れて死ぬかと思ったんですが、最初からnginxについてはログローテーションが設定されているため気にしなくてOKです。minecraft-serverについてはどうなるかわかりませんので、必要に応じてlogrotateを設定して対応したほうが良いと思います。
https://genchan.net/server/4907

まとめ

いろいろ調べながらで時間がかかりましたが、3時間ほどでゼロ知識の状態からでもマインクラフトのマルチプレイサーバーを立てることができました。現在のところ無事快適に遊べています\(^o^)/

こういう自分の趣味嗜好のために技術を勉強すると非常に捗るのでオススメですね。みなさんもゲームを楽しみながら技術を勉強して一石二鳥になりませんか\(^o^)/


2016年1月7日木曜日

Asset Catalog を使用しているときは [UIImage imageNamed:] が遅くなることがある

タイトルのとおりですが、本日発見してひどくパフォーマンスに影響が出たため注意喚起を兼ねて共有いたします。

最近のiOSプロジェクトは全て画像をxcassetsすなわちAsset Catalog経由で管理することが多いかと思いますが、このAsset Catalogを使用している際に[UIImage imageNamed:]経由で画像を取得するとiOS 8以前とは異なり大変画像の取得が遅くなることがあるようです。

詳細はこちら。
https://forums.developer.apple.com/thread/17888

実際に私の環境では目に見えて遅くなりました。Instruments経由で計測したところ最大で10倍ほど差が出ているように見えました。iOS 9.1以降は修正されているとのことですが、それでも[UIImage imageNamed:inBundle:compatibleWithTraitCollection:]を使用したほうがパフォーマンスへの悪影響が少ないとの情報があります。実際Instruments上でもTrait Collectionを検索するのに無駄なパワーを使っているように見えたのでパフォーマンスがタイトな箇所では自分で非同期ロードするなりキャッシュするなりして補ってあげたほうが良い気がします。

こちらからは以上です。

2015年12月17日木曜日

Xcode 7.2 の LLDB で Swiftのデバッグをするコツ

現在のXcode 7.2でSwiftを使ったiOSアプリのデバッグをするときのコツみたいなものをまとめました。将来的にはより良くなる可能性はあります。というか良くなってほしいです(´・_・`)

■LLDBはbreakした地点によって挙動が変わる

まずハマりどころがこれですが、現在のLLDBはbreakした地点で実行されていたコードがSwiftのコードかC言語系のコードかによってモードが変わります。
// Objective-C mode
(lldb) po [someObject property]

// Swift mode
(lldb) e someObject.property
Objective-Cモードの時にSwiftっぽい呼び出しをしたり、その逆をしてもまともにLLDBは動作しません。なので現在自分がどちらのモードのLLDBにいるのかを判断するのがキモになります。

ハマりどころとして、例えば実行中におもむろに停止ボタンを押してみるとか、debug viewボタンを押してみると、全部のコードがSwiftで書かれているアプリにも関わらずいきなりLLDBがObjective-Cモードで起動します。これはbreakされるのがシステムのC言語で書かれた領域だからです。

ちなみに現在のモードがどちらかを判断する方法は無いような気がします。気合と慣れで判断してください。オープンソースになりましたし、そのうち改善されると思います\(^o^)/

■SwiftモードのLLDBでprint object (po) したい

SwiftモードのLLDBのpoはかなり微妙な実装になっているので、SwiftモードでLLDBを使う場合にはpoの代わりにexprすなわちeを使うことをオススメいたします。
(lldb) e someObject
参照: http://stackoverflow.com/questions/28016227/when-debugging-swift-code-can-i-get-a-typed-reference-to-an-object-given-just-i

なんかこちらの記事ですとe -O -d run --で実行するといいよって書いてますけど何が違うのかはよくわかってません。個人的には普通のeでだいたい問題なかったです。

■SwiftモードのLLDBでポインタアドレスからオブジェクトを起こしたい

Objective-Cであれば
po 0x123456789012beef
で終わりなんですが、SwiftモードのLLDBはそこまで面倒を見てくれません。そこでunsafeBitCast()関数が便利に使えます。
(lldb) e let $v = unsafeBitCast(0x123456789012beef, MyView.self)
(lldb) e $v
これではかどりますね。

レガシーな Objective-C プロジェクトを Swift なプロジェクトに変換する

ここで言うレガシーなObjective-Cプロジェクトの定義とは
  • iOS 7時代 (Xcode 5) より前に作成されたプロジェクトである
  • Swiftのコードを一行も含んでいない
  • IOS_DEPLOYMENT_TARGETが8.0よりも小さい (7.xをサポートしている)
とします。

こんな由緒正しいiOSのプロジェクトを未だにメンテしている人もなかなかいないのかと思いますが、もしいらっしゃいましたらそんな方のためにSwiftなプロジェクトに変換していく方法をメモしておきます。

■前提条件

まずIOS_DEPLOYMENT_TARGETを8.0以上にしましょう。IOS_DEPLOYMENT_TARGETを8.0以上にすることでdynamic frameworkおよびclang moduleが使えるようになるため、Objective-CとSwiftの間の垣根が非常に低くなります。

■ケース1: 根っこはObjective-Cのまま、Swiftのファイルを追加

普通にSwiftのファイルを追加したらXcodeが上手いことしてくれます。具体的には

clang moduleを有効にしてdyldを使えるようにする設定
CLANG_ENABLE_MODULES = YES;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";

Swift化されるターゲットごとにブリッジングヘッダを作成
SWIFT_OBJC_BRIDGING_HEADER = "myapp/myapp-Bridging-Header.h";

Releaseビルド以外に対して最適化レベル設定
SWIFT_OPTIMIZATION_LEVEL = "-Onone";

が自動的に行われるので後はせいぜいブリッジングヘッダに使ってるObjective-Cのヘッダを書き込む程度ですみます。

■ケース2: 根っこからSwiftにする

「根っこからSwift」とは要するにmain.m(C言語のmain関数)を持たないアプリにしたいということですが、これも実は思ったより簡単にできます。
  • AppDelegate.swiftファイルを作成する
  • 既存のObjective-Cで書かれたAppDelegateを継承て新しくswiftなAppDelegateを作成して、@UIApplicationMainアノテーションを付ける
  • main.mを消す
参考: http://stackoverflow.com/questions/31309249/how-to-convert-objective-c-appdelegate-to-swift

たったのこれだけでプロジェクトの根っこがSwiftな状態になります。簡単ですね。

■さらにSwift化をすすめる

とりあえずAppDelegate.swiftを作ることで根っこはSwiftになるのですが、せっかくだからAppDelegateをまるごとSwiftにしてしまいたいものです。ここでもし、
  • UIWindowをAppDelegate内部でカスタマイズしている
  • UIApplicationをmain.mでカスタマイズしている
などの場合はそのままだとSwiftで対応するのがちょっと面倒です。

まずUIApplicationについてはInfo.plistのNSPrincipalClassを変更することで任意のカスタムクラスに差し替える事が可能です。参考はこちら: http://stackoverflow.com/questions/31642956/how-to-detect-all-touches-in-swift-2

UIWindowについてはMain.storyboardを使わなければ勝手にUIWindowを差し込まれることはなくなるので問題ないのですが、それでは困ると言う場合はawakeFromNibとかを実装してその中で
@UIApplicationMain
class MyAppDelegate: NSObject, UIResponder, UIApplicationDelegate {
  var window: UIWindow?
  override func awakeFromNib() {
    super.awakeFromNib()
    guard let defaultWindow = self.window else {
      fatalError("Something is wrong")
    }
    let window = MySuperDuperWindow()
    window.rootViewController = defaultWindow.rootViewController
    self.window = window
  }
}
とかすれば動くと思います。多分。

2015年12月1日火曜日

pyspa Advent Calendar 2015: 2015 GOTY for Programmers

この記事は pyspa Advent Calendar 2015: 12/1 分の記事です。先鋒を担当いたしますakisuteこと小野と申します。よろしくお願いします。なんか3年前にも先鋒をやったような・・・

さて2015年も終わりに近づいてきたということで、本来はGame of the Year for akisuteというタイトルで私的に今年最高だったゲームについて延々と無駄に語ろうかと思っていたのですけれども、Qiitaでは利用規約には一切明記がありませんがプログラマーに役立たない記事は投稿できないという制約がございまして、大変遺憾ながらタイトルを無理やりプログラマーに役立ちますように変更させていただいた次第であります。

しかしながらご安心ください。今年2015年はプログラマー向けゲームの大豊作当たり年でございます。プログラマーにこれからなりたい人向け、プログラマーに育成したいお子さん向け、ガチのプログラマー勢向けのゲームを多数ご用意させていただきましたので最後までお楽しみいただければと思います。

それではまえがきはこの程度にいたしまして・・・いよいよ各賞の発表です!

■お子さんのプログラマー教育向け賞: CodeSpells


あなたのお子さんを将来プログラマーに育てたいと考えているのであればこのようなゲームはいかがでしょうか?というわけで自分で魔法を自由にプログラミングして使えるゲーム、CodeSpellsがノミネートです。こちらのゲーム自体はかなり昔から発表されていたのですが、Steam Early Accessが始まったのが今年のようなので今年のノミネートとさせていただきました。

ゲーム自体はオープンワールドのゲームで目的等はまだ特になく開発段階という感じですが、このゲームのキモである魔法を自由にプログラミングして行使する点は現在でもバッチリ遊べます。各魔法にはイベント・アクション・それから分岐とループの制御構造が用意されていて、例えば
  • 光の玉を正面に発射する
  • if 光の玉が何かに接触する
  • 自分自身を接触地点にワープ
とか、
  • for 100回ループ
  • 炎をi*3.6度方向に発射
とかいろいろ工夫して魔法が作れるようになっています。大人が遊ぶにはちょっとパズル要素がないとか目的がないとか現段階では問題点が多いのですが、子供が想像力を働かせて遊ぶという当初の目的上であれば自由に地面を隆起させたり石を吹き飛ばしたり津波を起こしたりして遊べるのではないかなと思います!

■プログラマー初心者向け賞: Human Resource Machine


World of GooやLittle Infernoなどで有名なTomorrow Corporationの新作、Human Resource Machineが今年のプログラマー初心者向け賞にノミネートしました!このゲームはどんな命令でもただ言われたとおりに働くただのサラリーマンのおっさんに簡単な命令セットを与えて目的を達成する、つまり
おっさんをプログラミングするゲーム
です!新しいな。

Tomorrow Corporationらしい独特の世界観がただただ言われたとおりに動くおっさんを彩り、一風変わった雰囲気を味わうことができます。この世界観だけでもこのゲームをやる価値があります。

さてこのおっさんを操るプログラミング言語(仮におっさん言語と呼ぶことにする)ですが、一般的なアセンブリ言語の命令セットと同じような感じになっています。またレジスタ兼RAMの代わりとして床のカーペット上の区画を自由に使うことができるようになっていて、ちょっと工夫すればこんなふうにおっさんにバブルソートをさせる事ができます!

おっさん言語のコーディングはビジュアライズされていて、各命令ラベルをドラッグアンドドロップするだけで快適にコーディングが楽しめます。コメントラベルも手書きで好きなように書けるようになっていて、プログラミングをやったことがないカジュアル層の人でも無理なく遊べます。反面ガチ勢の人には簡単すぎるかもしれません。一応命令セット数とステップ数の最適化チャレンジが用意されているので、ガチ勢の人はそちらで楽しんでみてはいかがでしょうか?

■自動化大賞: Factorio


皆様
プログラマーにとって
最も邪悪なことは何でしょうか?

手作業です!

皆様
プログラマーにとって
最も素晴らしいことは何でしょうか?

自動化です!

自動化こそ正義!
自動化こそ未来!
今こそゲームも自動化されるべき!!

ということで今年最も自動化が進んだゲームに送られる自動化大賞には、スーパーマリオメーカーを差し置いてFactorioがノミネートされました!

Factorioについて解説する前に少し前置きをさせてください。
皆様はMinecraftというゲームをご存知でしょうか?
今やスーパーマリオに肩を並べ、Minecraft系という一大ジャンルを作り上げた超有名作だと思います。

しかしながら私このMinecraftというゲームが大嫌いでして。

例えば鉄の武器が欲しいじゃないですか。
なので一生懸命地面を掘って鉄を探して、鉄が見つかったら今度は石炭を探して、持って帰ってきて自分でかまどにぶち込んで鉄にして、今度は鉄を自分で並べて装備を作って、また鉄が足りなくなったら自分で地下に潜って掘ってって繰り返して。

めんどくせえんだよ!!!!!!!
人力手作業で作業するからスケールしねえし!!!!!
自動で掘らせろや!!!!!!!!!

って思っちゃうんですね(´・_・`)

Factorioも基本的にはMinecraftのようなゲームです。
ある宇宙飛行士がとある惑星に不時着してしまって帰れなくなっちゃうんですね。
そこで現地の素材を集めて加工してサバイバルして、最終的にはロケットを作って打ち上げて星から脱出するのが目的のゲームです。
というわけで最初は木を斧で切り倒したり、鉄鉱石をツルハシで掘ったりするんですね。

違うのはここからです。
手作業で鉄を掘るとかめんどくさいじゃないですか。そもそもロケットを作るには膨大な料の鉄が必要だというのに手で掘るとか現実的じゃないですよね。
そこで主人公は鉄を掘るためのツルハシ・・・じゃなくて、なんと自動砕石機を作るんですね。
それから自動で材料を運ぶためのベルトコンベアと、自動で材料を加工してものを作成する機械と、自動で機械に燃料や材料を投下するロボットアームを作るんですね。
あとは砕石機からベルトコンベアで材料を運んで、ロボットアームで機械に投下すれば、自分が寝てても別の所を探検しててもエイリアンと銃撃戦を繰り広げてても勝手に新しい製品がドンドン製造されていくんですね。

なんて賢いんだこの主人公は!!!!!!!!!!

って思っちゃいますよね\(^o^)/

そう、このゲームは
自動化こそが正義
スケールする生産こそが正義
生産効率の最適化のために機械の配置を試行錯誤するのが正義

まさにプログラマーのプログラマーによるプログラマーのためのゲームなのです!

こうして最初は1秒間に1個しかつくれなかった鉄が、工場生産効率の改善とスケールメリットのおかげで最後には1秒に1万個以上生産できるようになります。ヤバい。
こうなってくるともう最適化欲求がドンドン高まってきて、そのうちロケットを打ち上げることが目標だったのが、1秒間に何発ロケットを打ち上げられるかみたいなゲームになってきて、資源を惑星の片っ端から鉄道で運搬し、邪魔するエイリアンを片っ端から銃弾爆薬戦闘ロボットの波で蹂躙し森林を伐採して燃やし・・・どっちが悪役かわからなくなってきましたね(´・_・`)

さらにこのゲームはゲーム内のオブジェクトがすべてコンソールからluaスクリプトで操作ができ、luaスクリプトを書くことで自由にMODをプログラミングすることができます。そのため究極的にはパソコンの前で座って眺めているだけで自動的に主人公が工場を作ってロケットを打ち上げてゲームをクリアするMODをプログラミングすることも理論上可能なわけです!

自動化万歳!!

■GOTY for Programmers: TIS-100


しかしながらそのFactorioを差し置いて、今年のGOTY for ProgrammersはこのTIS-100で決まりです!名前からしてプログラマーっぽいこのゲーム、簡単に説明しますと
  • 主人公(=あなた)の叔父に当たる人物が最近、原因不明の死を遂げた
  • 叔父は生前プログラマーで、遺品整理していたらTIS-100という1980年代製の謎のコンピュータが出てきた
  • TIS-100の中には叔父の生前のメッセージや日記などが残っていた
  • 主人公であるあなたはTIS-100のプログラムを復活させてすべての謎を解き明かしていく
という設定になっております。地味、地味の極地ですね。プログラマー以外眼中にない、まさにプログラマーの・プログラマーによる・プログラマーのためのゲームとしか言いようがありません。

この作品の焦点となるTIS-100コンピュータですが、通常の1980年台のコンピュータとは全く異なるユニークな分散コンピューティングアーキテクチャを採用しています。
  • 各プログラムは横に4つx縦に3つ、最大12個の「ノード」と、複数の「入力ポート」「出力ポート」で構成される
  • 各ノードは最大上下左右4つの「ポート」で結ばれている
  • 各ノードにはアセンブリ言語を用いて命令を記述できる
  • 各ポート間はGo言語のチャンネルのような仕様を用いて入力・出力を行ったり、各ノード間の協調動作を行ったりすることができる。
  • 各ノードの命令はすべて並列で実行される
このアセンブリ言語とモダンな言語の特性を併せ持ったアーキテクチャがTIS-100でのプログラミングの最大の面白さです。うまくコーディングしてノード間を並列させれば実行ステップ数を劇的に減らしたり、複数ノード間でちょっとしたmap-reduceのような作りさえ実現することができます。

しかしながらですね、このTIS-100
異常なほど難しい
んです

開発者Zachtronicsの前作はSpaceChemというゲームでして、こちらのゲームも後半異常な難易度になってくるのですが、本作TIS-100も負けず劣らず難易度が凄まじいことになります。主に難易度が高くなる原因として、TIS-100コンピュータのアーキテクチャ上の絶妙な制約があげられます。例えばこんな感じです:
  • 1ノード内にたったの15行しか書けない。ちなみに空行、ラベル行、およびコメントも1行として数えられます。
  • 1行に確か20文字だか30文字前後しか書けない。ラベル名等は極端に短くする必要がある。
  • 1ノードにレジスタが2つしかなく、そのうち片方は計算レジスタとして使用できずただ値を一時保存するしかできない。さらにこの一時保存レジスタと値をやり取りするだけで追加の1命令が必要。
  • INCL/DECL命令がない。
  • 上記制約が合わさって1ノード内でループ構造を作るのが著しく難しく、汎用のどこでも通用するループ構造を構成するのが難しい。
というわけで普通の手続き的なコードを書くことができず、まさにTIS-100のためのまったく新しいコーディングの仕方を考えていく必要があってとにかく辛いです。実際私は最後までクリア出来ていません(´・_・`)

このただでさえ高い難易度に加え、さらに各問題には最適化チャレンジというものがありまして、使用したノード数・使用した行数・実行ステップ数の3つの点からプログラムの最適化を全世界のプログラマと競うことができるようになっています。おかげで世界中でドハマりするプログラマーが続出。ついにハッカーズマニュアルやらC言語製のシミュレータ、果てはWeb上で動作するTIS-100用コードエディタがまでが登場してしまいました。捗る!

ぜひ我こそはというガチ勢のプログラマの皆様、年末年始のお休みはこのTIS-100の謎を解き明かすのに使ってみてはいかがでしょうか?

それでは皆様、来年もHappy Gaming!

2015年11月29日日曜日

iOS でヒラギノフォントが明示的に指定された時に描画サイズの計算が正しくならない問題を修正する

タイトルからして出落ち感が少々ありますが・・・

iOSのフォントサイズ計算には長年修正されないバグというか仕様がございまして、「ヒラギノフォント(ヒラギノ角ゴシック、ヒラギノ明朝等)」が明示的に[UIFont fontWithName:size:]で指定されたとき、そのフォントを使ったUILabelやUITextViewなどの描画サイズの計算が正しくならない問題があります。iOS 6からiOS 9.1現在に至るまでずっとなので今後も直ることはないと思います。

詳細についてはこちらの記事が詳しいです。
http://qiita.com/yusuga/items/2be8c55ca561bba44702
一番下のリンク先の記事でも同様の問題が訴えられていまして、それぞれ対策が記載されていますので合わせてご参照ください。

でまぁ、対処法としてはいくつかあります。
  • UIControl.contentVerticalAlignmentFillにする
  • sizeThatFitsおよびintrinsicContentSizeの実装を差し替える
  • ヒラギノフォントを明示的に指定するのをやめる。システムフォントを使えばいいじゃない\(^o^)/
  • システムが提供するヒラギノフォントを使うのをやめて、モリサワさんなどからまともなヒラギノフォントを買ってきてそちらを使う

今回は私が実際に使っているsizeThatFitsの実装を差し替える方法を紹介したいと思います。といってもまぁ結構簡単です。以下の様な実装になっています。

見ての通り、フォントファミリーがヒラギノ系であったら、
  • widthはceilする
  • heightはもともとの高さにfontのdescenderをfabsしてから足したうえでceilする
だけです。簡単でしょう? Apple爆発しろ

2015年10月30日金曜日

iOS デバイス上で YouTube の動画を扱うときの制限事項などまとめ

iOSのデバイス上でYouTubeの動画を扱うときに、PC上のブラウザとは異なった制約がかかる箇所がいくつかあるのでまとめておきます。

■iOSアプリでYouTube動画を扱いたいとき

youtube/youtube-ios-player-helper を使うのがもっともよいです。こちらはYouTube公式のライブラリとなっています。具体的な実装としてはUIWebViewを使い、その上にYouTubeのiframe APIを用いてiframeのプレイヤーをロードして表示する実装になっています。その他一部のAPIについてはObjective-C経由でそのまま呼び出せるようになっていて便利です。
こちらに動画ロード時に使えるパラメータの一覧があります。
またこちらにプレイヤーのAPIの一覧があります。
以上に記載がある機能は基本的に使えますが、一部例外があります。以下で説明します。

■iOSアプリでYouTube動画を扱いたいとき(AVFoundationで)

諦めてください。
実際にはやろうと思えば実は可能ですし巷にはそういうアプリもございますが、基本的にYouTubeが許可していない動画そのもののURLを直接探してきて叩く必要がありまして権利的に大変問題がございますので、まっとうなアプリを作ろうとお考えの方は潔く諦めていただくことを強くおすすめいたします。ただリジェクトはされていないところを見るとApple的にはYouTubeの都合なんぞ知ったこっちゃないというスタンスのようです。

■YouTube動画をインラインで表示したい

普通に問題ありません。ロード時にplaysinlineパラメータを1に設定しましょう。

■YouTube動画のUIをカスタマイズしたい

諦めましょう。インライン再生でもフルスクリーン再生でも、最初から用意してある見た目を使うしかありません。ただしコントロールを表示するしない程度はカスタマイズ可能です。ロード時にcontrolsやfsパラメータを渡しましょう。

■YouTube動画の一部だけを再生したい

可能です。ロード時にstartパラメータとendパラメータを指定すればオッケーです。

■YouTube動画を複数同時再生したい

複数のYouTube動画を並べるぶんには問題ありませんが、同時に再生となるとあんまり自信がないです(実機で試せていません)。ちなみにAndroidの場合はできないそうです。

■YouTube動画をオートプレイしたい

アプリであれば可能ですが、iOSのSafariでは不可能です。実装上許可されていません。
アプリの場合はUIWebViewのallowsInlineMediaPlaybackをYESに設定すればautoplayオプションが有効になります。先ほどのyoutube-ios-player-helperはこちらのオプションが有効になっています。

■YouTube動画をプログラム的にフルスクリーンに切り替えたい

いわゆる標準のフルスクリーンプレイヤーを使うという意味では不可能です。諦めてください。
詳細はこちら。
ワークアラウンドとしては、

  • 最初からフルスクリーンで表示する(これは可能です)
  • ボタンを押したら一旦現在の動画をアンロードして、フルスクリーンとして再度一からロードする(可能ですが遅いです)
  • プレイヤー領域を司るHTMLを操作してフルスクリーンに見せかける

などがあります。

■YouTube動画をミュートしたい

不可能です。諦めてください。
詳細はこちら。
AVFoundationの機能などを使っても基本的にアプリ全体をミュートにすることはできません。AVAudioSessionのmodeをAVAudioSessionModeMeasurementにすることでアプリ全体のオーディオプレイバックを止めるという裏ワザもありますが、この方法を使うとビデオの再生まで止まってしまうので意味が無いです。
ただしデバイスのmuteスイッチの状態やデバイス全体の音量は普通に動画の音量に反映されますのでご安心ください。