ごらくらいふ

プログラミングしたりゲームしたり

StackViewで等サイズ等間隔で要素を配置する

stackviewを使って等サイズ等間隔に要素を配置したい。

パターン

  • StackView + Constraints
  • StackView
    • こっちのほうが好き

StackView + Constraints

  • StackViewに要素を配置し、要素同士をEqual widthsで揃える
  • 要素間の間隔はStackViewのプロパティSpacingで調整する

f:id:yajamon:20161003171207p:plain f:id:yajamon:20161003171415p:plain

StackView

  • StackViewに要素を配置し、StackViewのプロパティDistributionFill Equallyにする
  • 要素間の間隔はStackViewのプロパティSpacingで調整する

f:id:yajamon:20161003172309p:plain f:id:yajamon:20161003172325p:plain

所感

Constraintsを定義する必要がない後者の手法が好き。

putty形式の公開鍵をOpenSSH形式に変換してサーバにSCPアップロードする

(あーやべーなーパスワードログインできるままだなー)

個別に記事になってたのでひとまとめした

# Putty形式 -> OpenSSH形式
ssh-keygen -i -f id_rsa_putty.pub > id_rsa.pub
# scp [オプション] [ユーザ名]@[ホスト名]:[ファイル名] [ローカルパス (.)はカレント]
scp -P 22 id_rsa.pub user@hostname:~
余談
  • Putty形式の鍵をOpenSSH形式に変換する際、公開鍵からコメントが削げ落ちた
    • gglとSSH1ではコメントも鍵に含まれてたとか出て戦々恐々してたが、SSH2なので勝手に追記しても問題なかった
  • SCPについて、参考記事にある記法とMacにあるSCPのヘルプが異なっていて不安(うまくいったが…)

参考URL

puttyの公開鍵をOpenSSH形式に変換する | misty-magic.h

ssh でファイル転送(SCP コマンド) - Hidde’s Tips

ヤフオク!にて、ライブチケットなどに対する違反商品通報の対策

シンデレラガールズ4th live、楽しみですね。

http://idolmaster.jp/event/cinderella4th.php

チケットは無事入手できましたでしょうか。 私は無事会場チケット戦線に敗れ、いまライブビューイングチケットの抽選に祈りを捧げています。 (2016/08/22追記:ライブビューイングのチケット取れました( `ω')q)

もうひとつライブチケットに対して行っていることがありました。 オークションにおける転売チケットの違反通報です。

作業中、工夫して転売努力を注ぐ例に遭遇しました。

新着アラートに抗う

チケットが取れなかったプロデューサー(以下、P)の気持ちになれば、 買うPも通報するPも転売チケットを探すためにほぼ同じキーワードを指定します。

また、熱心に探すPはアラートを即通知するよう設定していますので、出品したらあまり間を置かずに発見されます。

通報されたら取り消し

出品者は、違反商品の申告通知を受けることができます。

ヤフオク!ヘルプ - 違反商品として申告があった場合

通知を受けたらオークションを取り消し、一旦静観したあと再度オープンします。 再オープンは新着アラートのように通知されないため、通知ベースで動く通報側から逃れることができます。

対策

オークションを取り消した段階で、通報側に通知メールが届きます。

私はGmailを使っていますので、このメールにスターを付け、定期的に再確認をしています。 再オープンされていたら再度通報し、メールからスターを外します。

出品したら即取り消し

出品したら即座にオークションを取り消し、しばらく寝かせたあと再度オープンします。 「もう通報されたかな?」という勘違いを狙う感じでしょうか。

対策

新着通知メールにスターをつけます。 通報後の再出品と方法は変わらないので、定期的に確認します。

宣伝

ヤフオク!での通報もなんだかんだ面倒なところがあります。 理由に「その他」を選んで、その他の中から適切なものを選んで……

ひとつふたつならまだ我慢できても、数が多ければ嫌気がさします。

なのでセミオートに通報できるChrome拡張を作りました。

github.com

個人の通報では限界があるので、ひとりでも違反商品の通報人が増えるといいんじゃないかな。

CocoaPods Linking error 「ld: symbol(s) not found for architecture i386」

環境

現象

CocoaPodsを導入して、いざdebug-buildしたら記事タイトルのエラーが発生した。

以下はそのログである。

Undefined symbols for architecture i386:
  "_FBSDKAppEventParameterNameContentType", referenced from:
      -[MyViewController viewDidLoad] in MyViewController.o
  "_FBSDKAppEventParameterNameCurrency", referenced from:
      -[MyViewController viewDidLoad] in MyViewController.o
  "_OBJC_CLASS_$_FBSDKAppEvents", referenced from:
      objc-class-ref in MyAppDelegate.o
      objc-class-ref in MyViewController.o
  "_OBJC_CLASS_$_FBSDKApplicationDelegate", referenced from:
      objc-class-ref in MyAppDelegate.o
  "_OBJC_CLASS_$_FBSDKGraphRequest", referenced from:
      objc-class-ref in MyClass.o
  "_OBJC_CLASS_$_FBSDKLoginButton", referenced from:
      objc-class-ref in MyViewController.o
ld: symbol(s) not found for architecture i386

結論

プロジェクト設定にて「Build Active Architecture Only」の項目が、Podsプロジェクトの設定と一致していなかったことが原因だった。

before

MyProject
  • Build Settings
    • Architectures
      • Build Active Architecture Only
        • Debug
          • NO
        • Release
          • NO
Pods
  • Build Settings
    • Architectures
      • Build Active Architecture Only
        • Debug
          • YES
        • Release
          • NO

after

MyProject
  • Build Settings
    • Architectures
      • Build Active Architecture Only
        • Debug
          • YES
        • Release
          • NO
Pods
  • Build Settings
    • Architectures
      • Build Active Architecture Only
        • Debug
          • YES
        • Release
          • NO

解決

Architecturesが「Standard architecures(armv7, arm64)」の状態で「Build Active Architecture Only」がYESの場合、 armv7, arm64だけを対象にビルドするっぽい。

Product>ArchiveではRelease設定を使うようにしているので、こちらでは「Build Active Architecture Only」をNOにしておこうと思う。

参考リンク

FacebookSDK 3.x -> 4.x : FBRequestConnection startWithGraphPath:completionHandler:が無くなったので FBSDKGraphRequest startWithCompletionHandler:を使う

記事タイトルキャメルケースでキッツキツだな。

結論

3.xにてGraphAPIを手軽に叩くため、FBRequestConnection startWithGraphPath:completionHandler:を使っていた。

4.xでは失くなってしまったのでFBSDKGraphRequest startWithCompletionHandler:を使った。

コードで見る違い

3.x

- (void) callGraphApi:(NSString*)graphPath {
    [FBRequestConnection startWithGraphPath:graphPath completionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
    }];
}

4.x

- (void) callGraphApi:(NSString*)graphPath {
    // 一個一個変数化するとデバッグしやすくて好き
    FBSDKGraphRequest* fbRequest = [[FBSDKGraphRequest alloc] initWithGraphPath:graphPath parameters:nil];
    [fbRequest startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
    }];
}

「なんでじゃ」と思ったこと集

  • FBRequestConnectionでやってたことがFBSDKGraphRequestConnectionではなくFBSDKGraphRequestに納まっていたこと
  • FBSDKGraphRequest startWithCompletionHandler:のコールバック、FBSDKGraphRequestHandlerの定義がFBSDKGraphRequestConnectionにあったこと
  • よくみるとFBSDKGraphRequestConnectionFBSDKGraphRequestをimportしておらず、その逆だったこと
    • 依存の仕方が直感に沿わない…内部クラスかしら?って思った

FacebookSDK 3.x -> 4.x : FBLoginView無くなったのでFBSDKLoginButtonを使った

Facebook APIバージョン v2.0 が非推奨間近*1のため尻に火が点いている。 消火活動で代替処理がわかったっぽいので記録。

(追記:2016/07/21 22:13) 3.x のログイン(ログアウト)時の処理の認識が間違っていたので修正。 仮にログイン時にNavigationControllerにPushするような実装をしていたら「画面を戻ろうとしているのに戻れない」現象が発生するはず。

改修内容

3.xでの擬似コード

// TheViewController.h

#import <FacebookSDK/FacebookSDK.h>
@interface TheViewController : UIViewController<FBLoginViewDelegate>
@end
// TheViewController.m

@interface TheViewController()
@property (nonatomic) FBLoginView* loginView;

@end

@implementation TheViewController
- (void)viewDidLoad{
    self.loginView = [[FBLoginView alloc] init];
}
- (void)viewDidAppear:(BOOL)animated{
    // viewの位置を真ん中にちょちょいとする
    CGRect bounds = [UIScreen mainScreen].bounds;
    CGRect rect = self.loginView.frame;
    rect.origin.x = (bounds.size.width - rect.size.width) / 2.0;
    rect.origin.y = (bounds.size.height - rect.size.height) / 2.0;
    self.loginView.frame = rect;

    // delegateの指定
    self.loginView.delegate = self;

    // 読み込み権限の指定
    self.loginView.readPermissions = @[@"public_profile", @"read_stream"];

    // 表示
    [self.view addSubView:self.loginView];
}

// FBLoginViewDelegate
-(void)loginViewFetchedUserInfo:(FBLoginView *)loginView user:(id<FBGraphUser>)user{
    // (とくになにもしていなかった……)
}
-(void)loginViewShowingLoggedInUser:(FBLoginView *)loginView{
    // ログインしている状態でLoginViewを表示したときの処理
}
-(void)loginViewShowingLoggedOutUser:(FBLoginView *)loginView{
    // ログアウトしている状態でLoginViewを表示したときの処理
}
@end

4.xでの擬似コード

// TheViewController.h

#import <FBSDKCoreKit/FBSDKCoreKit.h>
#import <FBSDKLoginKit/FBSDKLoginKit.h>
@interface TheViewController : UIViewController<FBSDKLoginButtonDelegate>
@end
// TheViewController.m

@interface TheViewController()
@property (nonatomic) FBLoginView* loginView;
@property (nonatomic) BOOL isLoggedIN;

@end

@implementation TheViewController
- (void)viewDidLoad{
    self.loginView = [[FBLoginView alloc] init];
}
- (void)viewDidAppear:(BOOL)animated{
    // viewの位置を真ん中にちょちょいとする
    self.fbLoginButton.center = self.view.center;

    // delegateの指定
    self.fbLoginButton.delegate = self;

    // 読み込み権限の指定
    self.fbLoginButton.readPermissions = @[@"public_profile", @"read_stream"];

    // 表示
    [self.view addSubView:self.fbLoginButton];

    // ログイン状態による処理分けはここに移植する
    if([FBSDKAccessToken currentAccessToken]) {
    } else {
    }
}

// FBSDKLoginButtonDelegate

-(BOOL)loginButtonWillLogin:(FBSDKLoginButton *)loginButton{
    // ログイン前処理
    // NOを返すと処理を中止するらしい。APIリファレンスに書いておいてほしい。
    return YES;
}
-(void)loginButton:(FBSDKLoginButton *)loginButton didCompleteWithResult:(FBSDKLoginManagerLoginResult *)result error:(NSError *)error {
    // ログイン処理を完了した時
    if (error) {
        return;
    }    
    if (result.isCancelled) {
        return;
    }
    if ([result.declinedPermissions containsObject:@"required permission"]) {
        return;
    }
    
    // ログイン完了
    // ログイン時の処理
}
-(void)loginButtonDidLogOut:(FBSDKLoginButton *)loginButton{
    // ログアウト完了
    // ログアウト時の処理
}
@end

*1:v2.1が公開されてから2年になるため

既存のXcodeプロジェクトにCocoaPodsを入れたらビルドエラー ld: library not found for -lPods

既存のプロジェクトにCocoaPodsを入れて、早速buildしたら次のようなエラーが出た。

ld: library not found for -lPods-ProjectName

対処方法をggrといくつかあって悩んだので、*1*2公式を確認した。

guides.cocoapods.org

Using the CocoaPods Project項目4 に答えがあった。

If Xcode complains when linking, e.g. Library not found for -lPods, it doesn't detect the implicit dependencies:
  • Go to Product > Edit Scheme
  • Click on Build
  • Add the Pods static library, and make sure it's at the top of the list
  • Clean and build again

以下にも続きがあるが、自分はこの時点で解決した。

他プロジェクトの生成物を使うので、先にbuildしましょう。ということかと。

Manage schemeで別途buildすると、「ライブラリのアップデートが反映されねぇ!」ってなりそうだからこっちの方法が良さそう。

*1:Manage schemeからPodsプロジェクトをshowするとか

*2:Edit schemeで対処するとか