NSNull and nil differ

今日のハマリ

さっき、cruxbookのv1.0.3のアップデートが公開されたのでウキウキしながらアップデートしました

これでやっと課題検索が動く…と、課題検索をしてみるとバッチリ動いています

しかし、その後の検索結果からの課題の詳細を見ようとするとアプリが落ちる!!!

なんでー?? テストの時はそんなことなかったのにな~ と思い焦りながらも、開発環境のソースコードのサービスアクセス先を本番環境のサーバに変えて試してみたところ、落ちた~!! デバッガーで追ってみると、どうやら課題のコメントが入力されていない場合に落ちる様子

課題詳細画面のcellForRowAtIndexPath:ではこんな処理をしている

[cpp]
// メモ
NSString *string = [self.problem valueForKey:@"comment"];
UITextView *view = (UITextView *)[cell viewWithTag:2];
if (view == nil) {
view = [[UITextView alloc] initWithFrame:CGRectMake(20, 10, 280, 280)];
view.tag = 2;
view.editable = NO;
view.backgroundColor = [UIColor clearColor];
[cell addSubview:view];
}
view.text = string;
[/cpp]

このstringが悪さをしているみたいだ。UITextViewがこれに対してなんらかの処理をしようとするときに落ちている。そんなわけで、最初はこのようにコードを変えてみた

[cpp]
// メモ
NSString *string = [self.problem valueForKey:@"comment"];
UITextView *view = (UITextView *)[cell viewWithTag:2];
if (view == nil) {
view = [[UITextView alloc] initWithFrame:CGRectMake(20, 10, 280, 280)];
view.tag = 2;
view.editable = NO;
view.backgroundColor = [UIColor clearColor];
[cell addSubview:view];
}
if (string) {
view.text = string;
}
[/cpp]

つまり、if (string != nil) と同じ解釈。でも、これでは不等式は成立せずにview.textにstringが代入されてしまう。結果、アプリも落ちる。調べてみたところ、このstringがnilなのかと思いきやそうでもないようだ

http://d.hatena.ne.jp/shoby/20110319/1300567422

こちらを参考に下記のように修正したところ、うまく動いた

[cpp]
// メモ
NSString *string = [self.problem valueForKey:@"comment"];
UITextView *view = (UITextView *)[cell viewWithTag:2];
if (view == nil) {
view = [[UITextView alloc] initWithFrame:CGRectMake(20, 10, 280, 280)];
view.tag = 2;
view.editable = NO;
view.backgroundColor = [UIColor clearColor];
[cell addSubview:view];
}
if (![string isEqual:[NSNull null]]) {
view.text = string;
}
[/cpp]

それはいいのだが、このアップデートが反映されるまでいますぐにアップデートを提出しても1週間はかかる!!! やべぇなぁ、どうしよう、と思ったんだけど、とりあえずサーバ側で

[sql]

sql> update problem set comment = ‘ ‘ where comment is null;

[/sql]

したったww これでとりあえず表示されている

UILabel appearance proxy. setFont deprecated

今日も元気にはま寿C!!

やりたいこと→アプリ全体のフォントを統一したい

どうやら調べてみるとiOS5からはappearance proxyっていうのがあるらしい

http://stackoverflow.com/questions/8707082/set-a-default-font-for-whole-ios-app

ふむふむ

[cpp]
[[UILabel appearance] setFont:[UIFont fontWithName:@"YourFontName" size:17.0]];
[/cpp]

みたいに書けばいいよ~とは書いてあるんだけど、どこに書くの??いや、当然

[cpp]
– (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions;
[/cpp]

っしょ、みたいな。。。とりあえず、試してみる(←これ大事)

[cpp]
– (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.

// URL REF: http://stackoverflow.com/questions/8707082/set-a-default-font-for-whole-ios-app
[[UILabel appearance] setFont:[UIFont fontWithName:@"Meiryo" size:16.0f]];

return YES;
}
[/cpp]

変わらないんけどー。チッ

さらに調べてみるとsetFontはdeprecatedだから~っていうのとappearance proxyを使えるのはUI_APPEARANCE_SELECTORが付けられたメソッドだけだから!っていうことを知る
(UI_APPEARANCE_SELECTORがついているかどうかはUILabel.h等のソースコードまで読め!!って事らしいです。ぷっ)

↑もはや同じ道を辿った人にしか理解できない文章になっている。でもいい、それだけのために存在しているので

なるほどなるほど

http://stackoverflow.com/questions/11308379/uiapperance-not-taking-effect-on-uilabels-created-programatically

だから?もっと具体的な解決法教えて!と思いながらさらにコメントを見ていくと、”こんなメソッド作ってUILabelのカテゴリーで実装すればいいんだよ~”ってのが書いてある。ふむふむ

カテゴリーね。なんかObjective-Cの入門書にチラっと紹介されてたな。Objective-C言語特有の拡張仕様だったな、たしか。なんか雰囲気的にJavascriptのprototypeっぽそう。まぁ、詳しくはObjective-C プログラミング言語(PDF)あたりを読むなりグーグル先生に教えてもらうなりしてくれ

そしていつもハマるのが、このコードの断片。どこに置くんだよ!!そこまで丁寧に教えてくれるとstackoverflow最高~って思えるんだけど。とりあえず、カテゴリーの定義ファイルの命名規則はクラス+カテゴリって感じらしい

[cpp]

@interface UILabel (UISS)
– (void)setTextAttributes:(NSDictionary *)numberTextAttributes UI_APPEARANCE_SELECTOR;
@end

@implementation UILabel (UISS)
– (void)setTextAttributes:(NSDictionary *)numberTextAttributes;
{
UIFont *font = [numberTextAttributes objectForKey:UITextAttributeFont];
if (font) {
self.font = font;
}
UIColor *textColor = [numberTextAttributes objectForKey:UITextAttributeTextColor];
if (textColor) {
self.textColor = textColor;
}
UIColor *textShadowColor = [numberTextAttributes objectForKey:UITextAttributeTextShadowColor];
if (textShadowColor) {
self.shadowColor = textShadowColor;
}
NSValue *shadowOffsetValue = [numberTextAttributes objectForKey:UITextAttributeTextShadowOffset];
if (shadowOffsetValue) {
UIOffset shadowOffset = [shadowOffsetValue UIOffsetValue];
self.shadowOffset = CGSizeMake(shadowOffset.horizontal, shadowOffset.vertical);
}
}
@end

[/cpp]

なのでこれをきっとUILabel+UISS.h、UILabel+UISS.mというファイルに書けばいいのだな

あとはsetFontの変わりに、これを使えば、上手くいくはず、、、、上手く行ってなかったらこのブログの投稿も存在しないだろう、とキレの良いみなさんは既に気づいているはずですね

[cpp]
#import "UILabel+UISS.h"

@implementation AppDelegate

– (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.

[[UILabel appearance] setTextAttributes:[NSDictionary dictionaryWithObject:[UIFont fontWithName:@"Meiryo" size:16.0f] forKey:UITextAttributeFont]];

return YES;
}
[/cpp]

恐る恐る⌘-Rしてみると、、、変わったー!!!

と、分かりきった結果ではありますが、これで無事アプリ内のUILabelが全てメイリオ(Meiryo)フォントになりました~

UITableView delegate methods

ハマったーいむ とぅーるるるっ

今日の浜ちゃん

UITableViewのUITableViewCellの中のフォントを変えたいんです。ふぉんとにすごく簡単なこと。コードはこんな感じ

[cpp]
– (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *cellIdentifier = @"cell";
UITableViewCell *cell = [_tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}

UIFont *myFont = [UIFont fontWithName:@"Meiryo" size:8.0f];
cell.textLabel.font = myFont;

return cell;
}
[/cpp]

しかーし、実行してみるとちっとも小さくなっていない。もしかして、小さくなっているけど私が認識していないだけ?とか思ってフォントサイズを2.0fとか極端に小さくしちゃったりしてね。でも変わらない!!なぜだ。あーイライラする

と思ってコードを見渡すと違う箇所でこんな事してた、自分

[cpp]
– (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
cell.backgroundColor = [UIColor whiteColor];
cell.textLabel.font = [UIFont fontWithName:@"Meiryo" size:12.0f];
UIView *bgColorView = [[UIView alloc] init];
[bgColorView setBackgroundColor:[UIColor colorWithRed:41/255.0f green:47/255.0f blue:61/255.0f alpha:1.0f]];
[cell setSelectedBackgroundView:bgColorView];
}
[/cpp]

あー、いつしか昔、何故か忘れたけど、cellの外観を統一するためにwillDisplayCell:をオーバーライドしていたのであった。これはcellが表示される直前に呼び出されるので当然cellForRowAtIndexPath:より後に実行されるのでいくらcellForRowAtIndexPath:の中でフォント変えても意味なかったんだった。ふぉんとバカねぇ、あんた!!

一つのControllerの中のコードが多くなってくると、こういった罠に陥りやすいので注意が必要。特にXcodeを使っていると長いメソッドとか滅多に改修しないコードは折りたたんで非表示にしてしまっているケースもありえるので、さらに注意が必要。私自信は折りたたみ機能は使わないが

これからはもっと#pragma markをうまく使ってソースコードの可読性をよくするように心がけよう

たまにクライミングジムに行くとこういうズボン履いてる人いるよね。登りやすいのかな~?見てるとホールドに引っかかりそうで