コンテンツへ移動
2012/05/27

core-plot 使ったアプリのArchive方法


core-plot を自分のプロジェクトに組み込むとき、Googleの下記のドキュメントに従えば、core-plotのプロジェクトを自分のプロジェクトに取り込むことになる。
Using Core Plot Within an Application

しかしこのままだとArchiveしたものは複数のプロダクトを含んでいるという以下のようなメッセージが出てValidateやSubmitできる形にならない。

App Name does not contain a single–bundle application or contains multiple products. Please select another archive, or adjust your scheme to create a single–bundle application.”

解決方法は以下のサイトにかいてあったので、メモ。

Xcode 4 – Problem Submitting App With Static Library

2012/05/12

core-plot scatter での小技メモ


1)Y軸のラベルを固定(スクロールしない)

CPTXYAxis *y = axisSet.yAxis;
y.axisConstraints = [CPTConstraints constraintWithLowerOffset:0.0];

2)Y軸のmajorIntervalLengthにグリッドをひく
lineStyleをなにか設定して。

CPTXYAxis *y = axisSet.yAxis;
y.majorGridLineStyle = lineStyle;

3)グリッドのベース線とグリッド線を値の最大のところまでのみ表示

y.visibleRange   = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromInteger(0)
length:CPTDecimalFromInteger(yの最大値)];
y.gridLinesRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromInteger(0)
length:CPTDecimalFromInteger(xの最大値)];

※y.gridLinesRangeはxの最大値であることに注意

4)y軸方向にはスクロールしない、かつXは0以下にスクロールしない
ヘッダに <CPTPlotSpaceDelegate>を追加して、

-(CGPoint)plotSpace:(CPTPlotSpace *)space willDisplaceBy:(CGPoint)displacement
{
    CGFloat x = displacement.x;
    float loc = [[NSDecimalNumber decimalNumberWithDecimal:[((CPTXYPlotSpace*)space).xRange location]] floatValue];
    if (loc < 0 && x > 0) x = 0;
    return CGPointMake(x, 0);
}
-(CPTPlotRange *)plotSpace:(CPTPlotSpace *)space willChangePlotRangeTo:(CPTPlotRange *)newRange forCoordinate:(CPTCoordinate)coordinate
{
    if (coordinate == CPTCoordinateY) {
        newRange = ((CPTXYPlotSpace*)space).yRange;
    }
    return newRange;
}

参考:
iphone – Core plot disable y axes scaling, scrolling – Stack Overflow
iphone – Allow horizontal scrolling only in the core-plot barchart? – Stack Overflow の最後のコメント

2012/04/07

UITapGestureRecognizerとUIButton共用でかつダブルタップ対応の時


UITapGestureRecognizer でタップを検知するとき、シングルタップとダブルタップの両方に対応するために2つ登録する。

UITapGestureRecognizer* g1 = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTap:)];
g1.numberOfTapsRequired = 1;
g1.numberOfTouchesRequired = 1;
g1.delegate = self;
[self.view addGestureRecognizer:g1];

UITapGestureRecognizer* g2 = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleDoubleTap:)];
g2.numberOfTapsRequired = 2;
g2.numberOfTouchesRequired = 1;
[self.view addGestureRecognizer:g2];

でもこれだけだと、ダブルタップしたときにもhandleSingleTapを呼んでしまう。
そこで下記を書き足す。

[g1 requireGestureRecognizerToFail:g2];

これでダブルタップのときにhandleSingleTapは呼ばれなくなる。

さて、ここで、UIButton をこのViewに追加したくなるとする。しかし、UITapGestureRecognizerがあるせいで、UIButtonは反応しなくなってしまっている。
でこれを回避するためということで、以下を追加する。

g1.cancelsTouchesInView = NO;
g2.cancelsTouchesInView = NO;

ところが、これがうまく行かない。UIButtonはシングルタップを認識しない。しかし、UIButtonをダブルタップしてみると通る。
試しに、[g1 requireGestureRecognizerToFail:g2];を外してみたら正常にシングルタップでUIButtonが反応した。
理由はよくわからないがそうなっている。
でも、[g1 requireGestureRecognizerToFail:g2];を外すわけにはいかない。どうする?

ググってみて見つけた方法

UIButton inside a view that has a UITapGestureRecognizer
に書かれている。

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
if ([touch.view isKindOfClass:[UIButton class]]){
return FALSE;
}
return TRUE;
}

というのがそのまま使えた。
ヘッダに UIGestureRecognizerDelegate を追加して、 g1.delegete = self; すること。

2012/03/13

CoreDataで、あるコンテンツのリレーションしたタグの削除についてのメモ


エントリー Contents と
エントリー Tags があって、リレーションしている。つまり、
Contents* content として、content.tags を持っているとする。
なお、Tags には title アトリビュートがある、つまりTags* tag なら tag.title がある。

それで本題、 content.tags における tag.title = @”xyz” のものの削除手順。

NSString* title = @”xyz”;
NSSet* objSet = [content.tags filteredSetUsingPredicate:[NSPredicate predicateWithFormat:@"title == %@",title]];
[content removeTags:objSet]; // メソッドが自動でできている!
NSError* error = nil;
if (![content.managedObjectContext save:&error]) {
NSLog(@”Unresolved error %@, %@”, error, [error userInfo]);
abort();
}
NSEnumerator *enumerator = [objSet objectEnumerator];
Tags* tag;
while ((tag = [enumerator nextObject])) {
[managedObjectContext deleteObject:tag];
}
if (![managedObjectContext save:&error]) {
NSLog(@”Unresolved error %@, %@”, error, [error userInfo]);
abort();
}
という感じだろうか?未確認だがメモしておく。

2012/03/13

NSDictionaryの中のNSMutableArrayは有効か?


例えば

valuesSections = [NSDictionary dictionaryWithObjectsAndKeys:
[NSMutableArray arrayWithObjects:@"",@"",@"", nil],@”Section1″,
[NSMutableArray arrayWithObjects:@"", @"", nil],@”Section2″,
nil];

のような、NSMutableArrayをセットしたNSDictionary を作っておけば、このNSMutableArray は更新可能だろうか?つまり、

NSMutableArray* valus = [valuesSections objectForKey:@"Section1"];
[values replaceObjectAtIndex:1 withObject:@"New Text"];
[valuesSections setObject:values forKey:@"Section1"];

とできるか?
どうも、だめなようだ。replaceObjectAtIndexの行でエラーになる。
結局、

NSMutableArray* values = [NSMutableArray arrayWithArray:[valuesSections objectForKey:@"Section1"]];

としてから、

[values replaceObjectAtIndex:1 withObject:@"New Text"];

しないとだめなよう。

2012/03/06

UITableViewStyleGroupedでdrawRectを使う


UITableViewStyleGroupedはそれ自体使いでのある仕組みだけれど、単にUITableViewのsection headerを固定したいためだけに使いたくなることがある。「section headerの固定」というのはつまり、UITableViewStylePlainだと、テーブルのスクロール中でも「親切にも」あるセクションの表示中はそのセクションのsection headerがナビゲーションバーの下に常に表示されるようになっているのだけれど、そうではなくセクションの先頭行の上に「固定」していて欲しいことがあるということ。

UITableViewStyleGroupedであれば、上記の「固定」の状態になる。
しかし、UITableViewStyleGroupedのセルは角丸四角の特殊な形になってしまう。とりあえず、背景や角丸罫線を消すことはtableView側でできる。

self.tableView.backgroundColor = [UIColor whiteColor];
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
self.tableView.separatorColor = [UIColor clearColor];

問題はこの上でカスタマイズしたUITabelViewCellを作って drwaRectでなにか描画しても、この角丸四角の範囲の外側に描画したものは表示されないということ。

解決策は簡単、カスタマイズしたUITabelViewCellの中で、

self.backgroundView = [[UIView alloc] initWithFrame:CGRectZero];

とやる。これだけ。

参考にしたのは How to customize the background/border colors of a grouped table view?
下から3番目の投稿。

2012/03/03

NSArray count は int なので NSIntegarとの比較に注意


例えば NSIntegar inx という値があって NSArray* array の要素数と比較するとき、inx がマイナス値をとる場合があるときは注意しなければならいと今日知った。

たとえば、 inx = -2 で array の要素数が 5つだとして、もし

if (inx > [array count]) { }

みたいな比較を書いてしまうと、偽でなければならないのに実際の結果は真になってしまう。
これは [array count] が返すのは NSIntegar ではなく、int だからのようだ。
とりあえず、

NSIntegar count = [array count];
if (inx > count) { }

とすれば正しい結果が得られた。

フォロー

Get every new post delivered to your Inbox.