2012年11月アーカイブ

こんにちは。開発担当のICTFです。

先日、開発中のプログラムを実機で動作確認する為にXcodeから転送を行ないました。
普段はこれだけで実機側でアプリが起動するのですが、今回はなぜかどれだけ待っても起動しません。
その上Stopボタンを押してプログラムの停止を指示しているのに、一向にXcode側も終了してくれないのです。
結局デバイスをPCから取り外すしか手段はありませんでした。

何が間違っているのか分からないままXcodeやPCの再起動を行なったのですが、まったく改善しません。
この現象が発生するのはあるデバイスのみで、他のデバイスでは正常に実機で動作確認できるのです。
もう一点関係ありそうな点として、問題の実機(iPhone4s)はこのところ妙に動作が重く、アプリを1つ消すのにもプチプリーズしているような状態でした。

読者の皆さんはこの現象の原因は何であると予想されるでしょうか。











ーーーーーー
実際解決してみると「ああこんな事なのか」といった内容ですが、原因は単なる「デバイス側の容量不足」でした。
残容量を確認してみるとまったく残っておらず、試しにインストールしているアプリを手当たり次第に消去したところ問題を解決する事ができました。
数日前になりますが、Ketchapp!様サイトにて弊社Perfect listener -Voice player-をご紹介頂きました。
スクリーンショット 2012-11-18 22.13.47.png

説明書にも負けない程の詳細なご紹介を頂き、誠に有り難うございます。
記事の最後で頂いたご提案
 「Dropboxを経由せずに、端末内のアプリ間で直接データを受け渡しする」
事につきましては、是非前向きに検討させて頂きます。

絶対に聴き逃さない事を目標としたボイスプレイヤーアプリ
「Perfect listener -Voice player」と「Perfect listener Lite -Voice player-」
を今後とも宜しくお願い致します。

無料でダウンロードできるPerfect listener Lite -Voice player- が本日発売開始しました。
再生が5分までという制限付きですが、Perfect listenerの機能はすべて使用可能となっていますので、まずはLite版をお試し下さい。

こんにちは。開発担当のICTFです。

UINavigationControllerは画面をpushあるいはpopする際、自動的にスライドする様なトランジションが適用されます。
今回はそのトランジションをカスタマイズする方法についてご紹介します。
実装は様々なトランジションに対応できるような方法をとりますが、サンプルとしてフェードトランジションを実装します。

カスタムトランジションを実装するにあたり、次の点を重要視して設計します。
  • pushする際に設定したトランジションをpopする際に「自動で」適用する。
  • 一度(白など)一色にフェードアウトした後、次の画面がフェードインする。
UINavigationControllerに対してCATransitionを普通に適用した場合、表示中の画面と次の画面が一瞬混ざってしまいます。
場合によっては有効かもしれませんが、今回は汎用性の高い「一度何かしらの色に塗りつぶされた後に次の画面が表示される」という処理を目指します。
この塗りつぶし処理を実現するため、遷移元と遷移先の画面の間に一時的なUIViewControllerを挟みます。

それでは実装に入ります。
まず一時的な一色のUIViewControllerを実装します。
フェード以外のトランジションにもすぐ対応できるよう、基本的な処理はベースクラスに実装します。
準備としてCATransitionを使うため、

#import <QuartzCore/QuartzCore.h>

を追加して下さい。

【AnimViewBase.h】

// AnimNavigationControllerで用いるトランジション付き画面のベースクラス

@interface AnimViewBase : UIViewController

{

UIViewController* _nextViewController;

float _duration;

BOOL _navigationBarHidden;

}


-(id) initWithBaseViewController:(UIViewController*)baseViewController nextViewController:(UIViewController*)nextViewController color:(UIColor*)color duration:(float)duration backButtonTitle:(NSString*)backButtonTitle;


// トランジションアニメーションのデザイン

-(CATransition*) createTransition;


@end


【AnimViewBase.m】

@interface AnimViewBase ()


// トランジション開始タイマーイベント

-(void) onScheduleTransition;


@end


@implementation AnimViewBase


-(id) initWithBaseViewController:(UIViewController*)baseViewController nextViewController:(UIViewController*)nextViewController color:(UIColor*)color duration:(float)duration backButtonTitle:(NSString*)backButtonTitle;

{

if (self = [super init]) {

_nextViewController = [nextViewController retain];

_duration = duration;

self.view.backgroundColor = color;

self.title = baseViewController.title;

// ナビゲーションバーのデザイン

if (backButtonTitle) {

UIBarButtonItem* backButton = [[[UIBarButtonItem alloc] init] autorelease];

backButton.title = backButtonTitle;

self.navigationItem.backBarButtonItem = backButton;

}

// トランジションアニメーションのデザイン

[baseViewController.navigationController.view.layer addAnimation:[self createTransition] forKey:nil];

}

return self;

}


-(void) viewWillAppear:(BOOL)animated

{

[super viewWillAppear:animated];

_navigationBarHidden = self.navigationController.navigationBarHidden;

self.navigationController.navigationBarHidden = YES;

}


-(void) viewWillDisappear:(BOOL)animated

{

[super viewWillDisappear:animated];

self.navigationController.navigationBarHidden = _navigationBarHidden;

}


-(void) viewDidAppear:(BOOL)animated

{

[super viewDidAppear:animated];

// トランジション開始スケジュール

[NSTimer scheduledTimerWithTimeInterval:_duration * 0.5 target:self selector:@selector(onScheduleTransition) userInfo:nil repeats:NO];

}


// トランジション開始タイマーイベント

-(void) onScheduleTransition

{

[self.navigationController.view.layer addAnimation:[self createTransition] forKey:nil];

if (_nextViewController) {

// 進む遷移

[self.navigationController pushViewController:_nextViewController animated:NO];

[_nextViewController release];

_nextViewController = nil;

}

else {

// 戻る遷移

[self.navigationController popViewControllerAnimated:NO];

}

}


// トランジションアニメーションのデザイン

-(CATransition*) createTransition

{

return nil;

}


@end


createTransitionが空実装ですが、これは派生先のクラスで実装します。
次にフェードトランジションを行なう派生クラスを実装します。

【FadeInOutViewController.h】

#import "AnimViewBase.h"


@interface FadeInOutViewController : AnimViewBase

{

}


@end


【FadeInOutViewController.m】

- (void)viewDidLoad

{

    [super viewDidLoad];

}


- (void)didReceiveMemoryWarning

{

    [super didReceiveMemoryWarning];

    // Dispose of any resources that can be recreated.

}


// トランジションアニメーションのデザイン

-(CATransition*) createTransition

{

CATransition* transition = [CATransition animation];

transition.duration = _duration * 0.5;

transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault];

transition.type = kCATransitionFade;

return transition;

}


@end


基本機能はベースクラスで実装済みなので、createTransitionの実装のみです。

最後に重要な機能である「push時のトランジション設定を、pop時にも自動的に適用する」
機能を実装します。
UINavigationControllerを継承し、popViewControllerAnimated:をオーバーライドします。

【UINavigationControllerEx.h】

@interface UINavigationControllerEx : UINavigationController


@end


【UINavigationControllerEx.m】

#import "AnimViewBase.h"


@interface UINavigationControllerEx ()


@end


@implementation UINavigationControllerEx


- (UIViewController *)popViewControllerAnimated:(BOOL)animated

{

if (self.viewControllers.count > 1) {

UIViewController* prevView = [self.viewControllers objectAtIndex:self.viewControllers.count - 2];

if ([prevView isKindOfClass:[AnimViewBase class]]) {

// トランジション画面クラスの場合、トランジション設定を取得する

[self.view.layer addAnimation:[((AnimViewBase*)prevView) createTransition] forKey:nil];

animated = NO;

}

}

return [super popViewControllerAnimated:animated];

}


@end


pop直前に一つ前の画面を調べ、AnimViewBaseを継承するクラスであった場合にトランジションを適用します。

使用方法は以下の通りです。

1. UINavigationControllerの生成処理をUINavigationControllerExに変更する

UINavigationControllerEx* navigationController = [[[UINavigationControllerEx alloc] initWithRootViewController:view] autorelease];


2. トランジションを加えたい画面遷移に、FadeInOutViewControllerを使用する。

NextView* NextView = [[[NextView alloc] init] autorelease];

FadeInOutViewController* fadeView = [[[FadeInOutViewController alloc] initWithBaseViewController:self nextViewController:NextView color:[UIColor whiteColor] duration:0.8 backButtonTitle:@"戻る"] autorelease];

[self.navigationController pushViewController:fadeView animated:NO];


注意事項として、pushViewControllerのanimatedはNOにして下さい。


こんにちは。開発担当のICTFです。

nend広告SDKのNADViewですが、release前にdelegateにnilを設定しなければならないですよね。
この初期化を忘れてしまうと、次回広告読み込み時にdelegateとして設定しているオブジェクトが無い為にアプリが不正終了してしまいます。
落ちるタイミングが広告読み込み時であるため、一見何も操作していないのに突然落ちるという少し厄介な不具合となってしまい、おっちょこちょいな私としてはこれまでに結構な時間を取られてしまっています。

今回はこの忘れがちなNADView.delegate = nilの処理を自動化しようと思います。
これが実装できればNADViewを張って、剥がしてのみ考えれば良いので楽になります。
仕組みは単純で、NADViewExというUIViewを継承したクラスを作り、NADViewExにNADViewを貼付けます。
画面から剥がされるとNADViewExのdeallocがコールされるので、その中でNADView.delegateにnilを設定します。

以下実装です。
【NADViewEx.h】

@interface NADViewEx : UIView

<NADViewDelegate>

{

NADView* _nadView;

}


-(id)initWithFrame:(CGRect)frame rootViewController:(UIViewController*)rootViewController;


@end


【NADViewEx.m】

- (id)initWithFrame:(CGRect)frame rootViewController:(UIViewController*)rootViewController

{

    self = [super initWithFrame:frame];

    if (self) {

// NADView

_nadView = [[NADView alloc] initWithFrame:frame];

[_nadView setNendID:NAD_KEY spotID:NAD_ID];

[_nadView setBackgroundColor:[UIColor clearColor]];

[_nadView setRootViewController:rootViewController];

[_nadView setDelegate:self];

[_nadView load:nil];

[self addSubview:_nadView];

    }

    return self;

}


-(void) dealloc

{

_nadView.delegate = nil;

[_nadView release];

[super dealloc];

}


// Adの初回読み込み完了

-(void) nadViewDidFinishLoad:(NADView *)adView

{

NSLog(@"Ad初回読み込み成功");

}


// Adの読み込み完了通知

-(void) nadViewDidReceiveAd:(NADView *)adView

{

NSLog(@"Ad読み込み成功");

}


// Adの読み込み失敗通知

-(void) nadViewDidFailToReceiveAd:(NADView *)adView

{

NSLog(@"Ad読み込み失敗");

}


@end


不正終了周りの面倒な心配が消えますので、是非使ってみて下さい。