@blog.justoneplanet.info

日々勉強

Xcode 5.1にアップデートするとビルドできなくなる

arm64に対応していないものが原因である。

■Build Settings>Architectures

CocoaPodsに対応するため以下の部分を

$(ARCHS_STANDARD)

以下のように修正する。

$(ARCHS_STANDARD_32_BIT)

変更後、以下のコマンドを実行する。

pod update

■JSONKit

isa is deprecatedと表示されてビルドできないので、Podfileに以下を追記する。ちなみにcompiler flagに-ferror-limit=0を設定してもビルドできない。

post_install do |installer_representation|
    installer_representation.project.targets.each do |target|
        target.build_configurations.each do |config|
            config.build_settings['CLANG_WARN_DIRECT_OBJC_ISA_USAGE'] = 'YES'
        end
    end
end

JSONKitをやめてNSJSONSerializationにしたいのだが某SDKが使用しているので諦める。

■OpenSSL

OpenSSL-for-iPhoneを再ビルド

cd OpenSSL-for-iPhone/
vim ./build-libssl.sh

以下のように修正する。というかmasterからpullすると7.1になっている。

VERSION="1.0.1e"                                                          #
SDKVERSION="7.1"           

以下のコマンドでビルドしてできるlibcrypto.aとlibssl.aで上書きする。

./build-libssl.sh

参考

iOSでOpenSSLを使って大きな数値計算をする

桁あふれしそうな数の計算をする。

■OpenSSLをiOS用にビルド

git clone https://github.com/x2on/OpenSSL-for-iPhone.git
cd OpenSSL-for-iPhone/
./build-libssl.sh

ビルドされたライブラリとヘッダーファイルをプロジェクトに追加する。

mkdir ../MyProject/Library/OpenSSL
cp -r include/ ../MyProject/Library/OpenSSL/include
cp -r lib/ ../MyProject/Library/OpenSSL/lib

Build Settings

Header Search Path

以下を追加する。

$(SRCROOT)/MyProject/Library/OpenSSL/include
Library Search Path

以下を追加する。

"$(SRCROOT)/MyProject/Library/OpenSSL/lib"

Build Phases

Link Binary With Libraries

libcrypto.aとlibssl.aを追加する。

■実装

#import <openssl/bn.h>

unsigned int rand = arc4random() % 100000000;
BIGNUM *random = BN_new();BN_set_word(random, rand);
BIGNUM *base = BN_new();BN_set_word(base, BASE);
BIGNUM *prime = BN_new();BN_set_word(prime, PRIME);
BIGNUM *remainder = BN_new();
BN_CTX *ctx;
ctx = BN_CTX_new();
BN_mod_exp(remainder, base, random, prime, ctx);
BN_CTX_free(ctx);

iOSでPythonが動けばいいのに。

参考

iTunes Connectで出力されるCrash Reportsを読む

■Crash Reportsの取得

iTunes Connect > Manage Your Apps > Current Version > View Details > Crash Reportsからcrashファイルをダウンロードして解凍、クラッシュ箇所を特定する。

■バイナリのビルド

以下の状態でビルドしたバイナリが必要である。

  • Build Settings の Strip Debug Symbols During CopyがNo
  • Build Settings の Strip Linked ProductがNo

但し、この状態でビルドすると30~50%ファイルサイズが大きくなるのでリリースビルドではNoにしておくべきである。

unzip hoge.ipa
cd Payload
xcrun atos -arch armv7 -o hoge.app/hoge 0x000ac264

以下のように出力される。

+[TAGResourceUtil expandResource:] (in hoge) + 586

Build Settingsを変更していないと以下のようになる。

___lldb_unnamed_function3890$$hoge (in hoge) + 586

参考

Mountain Lion上でCocoaPodsを導入する

メモ。

ln -s /usr/bin/gcc /usr/bin/gcc-4.2
sudo gem install cocoapods
pod setup
cd your_project
vim Podfile

以下のようにプラットフォームと使用するライブラリを記述する。

platform :ios,'6.0'
pod 'JSONKit','~> 1.4'

以下のコマンドでインストールする。

pod install

Podfileから特定のライブラリが削除されていれば、この時にライブラリが削除される。

ビルドできなくなる

以下の表示になってビルドが止まる。

library not found for -lPods

以下のコマンドでxcodeを起動すれば良い。

open your_project_name.xcworkspace/
  • your_project_name.xcworkspace
  • your_project_name.xcodeproj

libraryを入れるとビルドできなくなる

libraryを入れると以下のエラーが表示されてビルドできなくなる。

duplicate symbols for architecture i386

CocoaPodsで導入したライブラリと直接入れたライブラリが衝突している場合に起こる。直接入れたライブラリを削除する。

■PonyDebugger

サーバー

以下のコマンドでローカルのサーバーをインストールして動作させる。

curl -sk https://cloud.github.com/downloads/square/PonyDebugger/bootstrap-ponyd.py | python - --ponyd-symlink=/usr/local/bin/ponyd ~/Library/PonyDebugger

以下のコマンドで起動する。

ponyd serve --listen-interface=127.0.0.1

クライアント

vim Podfile

以下のようにライブラリを追記する。

platform :ios,'6.0'
pod 'PonyDebugger'

以下のコマンドでインストールを行う。

pod install

AppDelegate.m

#if DEBUG
#import <PonyDebugger/PonyDebugger.h>
#endif
PonyDebuggerがNotFoundでimportできない。

target header search pathsに$(inherited)を追記する。

#if DEBUG
    PDDebugger *debugger = [PDDebugger defaultInstance];
    [debugger enableNetworkTrafficDebugging];
    [debugger forwardAllNetworkTraffic];
    [debugger enableCoreDataDebugging];
    [debugger enableViewHierarchyDebugging];
    [debugger connectToURL:[NSURL URLWithString:@"ws://localhost:9000/device"]];
#endif

ブラウザでlocalhost:9000/deviceにアクセスする。

URL SchemeでiOSアプリを起動する

自分用のメモ。まず、プロジェクトのURL Typesを開きURL Schemesを追加する。2つ以上の場合はカンマで区切る。

AppDelegate.m

- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
    if ([[url scheme] isEqualToString:URL_SCHEME_HOGE] && [[url host] isEqualToString:URL_HOST_HOGE]) {
        // do something
    }
}

iOSでキーボードの表示と非表示に応じた処理をする

- (void)keyboardDidShow:(NSNotification *)note {
    // something
}
- (void)keyboardDidHide:(NSNotification *)note {
    // something
}
- (id)init {
    self = [super init];
    if (self) {
        // キーボードが表示された時
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidShow:) name:UIKeyboardDidShowNotification object:nil];
        // キーボードが隠れた時
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidHide:) name:UIKeyboardDidHideNotification object:nil];
    }
    return self;
}

iOSでUIViewのタップを検出する

■実装

以下のようにUITapGestureRecognizerを使う。

UITapGestureRecognizer *recognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onTapped:)];
[view addGestureRecognizer:recognizer];// view.tag == VIEW_HOGE_TAG

viewがタップされると以下のメソッドが実行される。

- (void)onTapped:(UITapGestureRecognizer *)recognizer {
    switch (recognizer.view.tag) {
        case VIEW_HOGE_TAG:
            // hogehoge
            break;
            
        case VIEW_FUGA_TAG:
            // fugafuga
            break;
            
        default:
            break;
    }
}

iOSのAddressBookを操作する

■グループの検索

CFArrayRef groups = ABAddressBookCopyArrayOfAllGroups(addressBook);
for (int i = 0; i < CFArrayGetCount(groups); i++) {
    ABRecordRef group = CFArrayGetValueAtIndex(groups, i);
    CFStringRef registerdGroupName = ABRecordCopyValue(group, kABGroupNameProperty);
    if (CFStringFind(registerdGroupName, aCFgroupName, kCFCompareCaseInsensitive).location != kCFNotFound) {
        isRegistered = true;
        registerdId = ABRecordGetRecordID(group);
    }
    CFRelease(registerdGroupName);
}
CFRelease(groups);

■グループの作成

NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
ABAddressBookRef addressBook = ABAddressBookCreate();
bool b1 = false;
bool b2 = false;
bool b3 = false;
ABRecordRef group = ABGroupCreate();
NSString *groupName = NSLocalizedString(@"APP_NAME", @"グループ名");
CFStringRef aCFgroupName = (__bridge CFStringRef)groupName;
b1 = ABRecordSetValue(group, kABGroupNameProperty, aCFgroupName, nil);
            
if (b1) b2 = ABAddressBookAddRecord(addressBook, group, nil);
if (b2) b3 = ABAddressBookSave(addressBook, nil);
if (b3) {
    [ud setInteger:ABRecordGetRecordID(group) forKey:@"key_ab_group_id"];
    [ud synchronize];
}
CFRelease(group);
CFRelease(addressBook);

■グループの削除

NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
ABAddressBookRef addressBook = ABAddressBookCreate();
bool b1 = false;
bool b2 = false;
ABRecordRef group = ABAddressBookGetGroupWithRecordID(addressBook, [ud integerForKey:@"key_ab_group_id"]);
b1 = ABAddressBookRemoveRecord(addressBook, group, nil);
if (b1) b2 = ABAddressBookSave(addressBook, nil);
if (b2) {
    [ud setInteger:0 forKey:@"key_ab_group_id"];
    [ud synchronize];
}
CFRelease(addressBook);

■グループのメンバ取得と削除

CFArrayRef people = ABGroupCopyArrayOfAllMembers(group);
for (int i = 0; i < CFArrayGetCount(people); i++) {
    ABRecordRef person = CFArrayGetValueAtIndex(people, i);
    result1 = ABGroupRemoveMember(group, person, nil);// グループから削除されるだけで電話帳には残る
    result2 = ABAddressBookRemoveRecord(addressBook, person, nil);// 電話帳から削除される
}

■グループへのメンバ追加

NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];

ABAddressBookRef addressBook = ABAddressBookCreate();
ABRecordRef group = ABAddressBookGetGroupWithRecordID(addressBook, [ud integerForKey:@"key_ab_group_id"]);
ABRecordRef person = ABPersonCreate();

CFStringRef aCFfirst       = (CFStringRef)first;
CFStringRef aCFsecond      = (CFStringRef)second;
CFStringRef aCFfirstYomi   = (CFStringRef)firstYomi;
CFStringRef aCFsecondYomi  = (CFStringRef)secondYomi;
ABRecordSetValue(person, kABPersonFirstNameProperty, aCFfirst, nil);
ABRecordSetValue(person, kABPersonFirstNamePhoneticProperty, aCFfirstYomi, nil);
ABRecordSetValue(person, kABPersonLastNameProperty, aCFsecond, nil);
ABRecordSetValue(person, kABPersonLastNamePhoneticProperty, aCFsecondYomi, nil);

ABAddressBookAddRecord(addressBook, person, &error);
ABAddressBookSave(addressBook, &error);

if ([ud integerForKey:@"key_ab_group_id"] != 0) {
    ABGroupAddMember(group, person, &error);
}

ABAddressBookSave(addressBook, nil);
CFRelease(person);
CFRelease(addressBook);

参考

iOSで本体の設定画面に設定項目を追加する

本体の設定画面にアプリの設定画面が出るアレであるが、Settings Bundleで検索すると色々出てくる。

■実装

NEW FILE … > Resource > Settings Bundleを追加する。この段階でシミュレータを立ち上げれば設定画面にアプリの設定項目が追加されている。

Root.plist

初期状態は以下のようになっている。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>PreferenceSpecifiers</key>
    <array>
        <dict>
            <key>Title</key>
            <string>Group</string>
            <key>Type</key>
            <string>PSGroupSpecifier</string>
        </dict>
        <dict>
            <key>AutocapitalizationType</key>
            <string>None</string>
            <key>AutocorrectionType</key>
            <string>No</string>
            <key>DefaultValue</key>
            <string></string>
            <key>IsSecure</key>
            <false/>
            <key>Key</key>
            <string>name_preference</string>
            <key>KeyboardType</key>
            <string>Alphabet</string>
            <key>Title</key>
            <string>Name</string>
            <key>Type</key>
            <string>PSTextFieldSpecifier</string>
        </dict>
        <dict>
            <key>DefaultValue</key>
            <true/>
            <key>Key</key>
            <string>enabled_preference</string>
            <key>Title</key>
            <string>Enabled</string>
            <key>Type</key>
            <string>PSToggleSwitchSpecifier</string>
        </dict>
        <dict>
            <key>DefaultValue</key>
            <real>0.5</real>
            <key>Key</key>
            <string>slider_preference</string>
            <key>MaximumValue</key>
            <integer>1</integer>
            <key>MaximumValueImage</key>
            <string></string>
            <key>MinimumValue</key>
            <integer>0</integer>
            <key>MinimumValueImage</key>
            <string></string>
            <key>Type</key>
            <string>PSSliderSpecifier</string>
        </dict>
    </array>
    <key>StringsTable</key>
    <string>Root</string>
</dict>
</plist>

■データの読み出し

以下のコードで設定値を呼び出すことが出来る。

NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
NSLog(@"%@", [ud objectForKey:@"name_preference"]);
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
NSLog(@"%@", [ud objectForKey:@"enabled_preference"]);
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
NSLog(@"%@", [ud objectForKey:@"slider_preference"]);

一番難しいのは何で検索すればこの画面の作り方に辿り着けるのかというところである。