Objective-Cのシングルトンは以前書いたけど、
dispatch_onceを使うとより簡単に書けるのでメモ。
Singleton.h
#import <Foundation/Foundation.h> @interface Singleton : NSObject + (Singleton *)instance; @end
Singleton.m
#import "Singleton.h"
@implementation Singleton
+ (Singleton *)instance {
static Singleton *instance_ = nil;
static dispatch_once_t predicate;
dispatch_once(&predicate, ^{
instance_ = [[self alloc] init];
});
return instance_;
}
@end
fullScreenImageメソッドで取得できる画像がちょっとおかしい。
initWithCGImage:scale:orientation:
でUIImage作って表示させると右に90度回転してる。
iOS4だとこの問題は起きない。
initWithCGImage
にすると、ちゃんと表示される。
でも、今度はiOS4系だと回転している。
iTunesで同期した画像はiOS5でもこの問題は起きない。
クラスリファレンスみるとiOS5で修正が入ったぽいが…。
まぁ、iOS4とiOS5の時で使い分ければいいんだけど何か釈然としない…。
NSString+Escape.h
#import <Foundation/Foundation.h> @interface NSString (Escape) - (NSString *)urlEncode; - (NSString *)urlDecode; - (NSString *)escapeHtml; - (NSString *)unescapeHtml; @end
NSString+Escape.m
#import "NSString+Escape.h"
@implementation NSString (Escape)
- (NSString *)escapeHtml
{
NSMutableString *string = [[self mutableCopy] autorelease];
[string replaceOccurrencesOfString:@"&" withString:@"&" options:NSLiteralSearch range:NSMakeRange(0, [string length])];
[string replaceOccurrencesOfString:@"<" withString:@"<" options:NSLiteralSearch range:NSMakeRange(0, [string length])];
[string replaceOccurrencesOfString:@">" withString:@">" options:NSLiteralSearch range:NSMakeRange(0, [string length])];
[string replaceOccurrencesOfString:@"\"" withString:@""" options:NSLiteralSearch range:NSMakeRange(0, [string length])];
return [NSString stringWithString: string];
}
- (NSString *)unescapeHtml
{
NSMutableString *string = [[self mutableCopy] autorelease];
[string replaceOccurrencesOfString:@""" withString:@"\"" options:NSLiteralSearch range:NSMakeRange(0, [string length])];
[string replaceOccurrencesOfString:@">" withString:@">" options:NSLiteralSearch range:NSMakeRange(0, [string length])];
[string replaceOccurrencesOfString:@"<" withString:@"<" options:NSLiteralSearch range:NSMakeRange(0, [string length])];
[string replaceOccurrencesOfString:@"&" withString:@"&" options:NSLiteralSearch range:NSMakeRange(0, [string length])];
return [NSString stringWithString: string];
}
- (NSString *)urlEncode
{
NSMutableString *string = [[self mutableCopy] autorelease];
[string replaceOccurrencesOfString:@"%" withString:@"%25" options:NSLiteralSearch range:NSMakeRange(0, [string length])];
[string replaceOccurrencesOfString:@";" withString:@"%3B" options:NSLiteralSearch range:NSMakeRange(0, [string length])];
[string replaceOccurrencesOfString:@"/" withString:@"%2F" options:NSLiteralSearch range:NSMakeRange(0, [string length])];
[string replaceOccurrencesOfString:@"?" withString:@"%3F" options:NSLiteralSearch range:NSMakeRange(0, [string length])];
[string replaceOccurrencesOfString:@":" withString:@"%3A" options:NSLiteralSearch range:NSMakeRange(0, [string length])];
[string replaceOccurrencesOfString:@"@" withString:@"%40" options:NSLiteralSearch range:NSMakeRange(0, [string length])];
[string replaceOccurrencesOfString:@"&" withString:@"%26" options:NSLiteralSearch range:NSMakeRange(0, [string length])];
[string replaceOccurrencesOfString:@"=" withString:@"%3D" options:NSLiteralSearch range:NSMakeRange(0, [string length])];
[string replaceOccurrencesOfString:@"+" withString:@"%2B" options:NSLiteralSearch range:NSMakeRange(0, [string length])];
[string replaceOccurrencesOfString:@"$" withString:@"%24" options:NSLiteralSearch range:NSMakeRange(0, [string length])];
[string replaceOccurrencesOfString:@"," withString:@"%2C" options:NSLiteralSearch range:NSMakeRange(0, [string length])];
[string replaceOccurrencesOfString:@"[" withString:@"%5B" options:NSLiteralSearch range:NSMakeRange(0, [string length])];
[string replaceOccurrencesOfString:@"]" withString:@"%5D" options:NSLiteralSearch range:NSMakeRange(0, [string length])];
[string replaceOccurrencesOfString:@"#" withString:@"%23" options:NSLiteralSearch range:NSMakeRange(0, [string length])];
[string replaceOccurrencesOfString:@"!" withString:@"%21" options:NSLiteralSearch range:NSMakeRange(0, [string length])];
[string replaceOccurrencesOfString:@"'" withString:@"%27" options:NSLiteralSearch range:NSMakeRange(0, [string length])];
[string replaceOccurrencesOfString:@"(" withString:@"%28" options:NSLiteralSearch range:NSMakeRange(0, [string length])];
[string replaceOccurrencesOfString:@")" withString:@"%29" options:NSLiteralSearch range:NSMakeRange(0, [string length])];
[string replaceOccurrencesOfString:@"*" withString:@"%2A" options:NSLiteralSearch range:NSMakeRange(0, [string length])];
return [NSString stringWithString: string];
}
- (NSString *)urlDecode
{
NSMutableString *string = [[self mutableCopy] autorelease];
[string replaceOccurrencesOfString:@"%2A" withString:@"*" options:NSLiteralSearch range:NSMakeRange(0, [string length])];
[string replaceOccurrencesOfString:@"%29" withString:@")" options:NSLiteralSearch range:NSMakeRange(0, [string length])];
[string replaceOccurrencesOfString:@"%28" withString:@"(" options:NSLiteralSearch range:NSMakeRange(0, [string length])];
[string replaceOccurrencesOfString:@"%27" withString:@"'" options:NSLiteralSearch range:NSMakeRange(0, [string length])];
[string replaceOccurrencesOfString:@"%21" withString:@"!" options:NSLiteralSearch range:NSMakeRange(0, [string length])];
[string replaceOccurrencesOfString:@"%23" withString:@"#" options:NSLiteralSearch range:NSMakeRange(0, [string length])];
[string replaceOccurrencesOfString:@"%5D" withString:@"]" options:NSLiteralSearch range:NSMakeRange(0, [string length])];
[string replaceOccurrencesOfString:@"%5B" withString:@"[" options:NSLiteralSearch range:NSMakeRange(0, [string length])];
[string replaceOccurrencesOfString:@"%2C" withString:@"," options:NSLiteralSearch range:NSMakeRange(0, [string length])];
[string replaceOccurrencesOfString:@"%24" withString:@"$" options:NSLiteralSearch range:NSMakeRange(0, [string length])];
[string replaceOccurrencesOfString:@"%2B" withString:@"+" options:NSLiteralSearch range:NSMakeRange(0, [string length])];
[string replaceOccurrencesOfString:@"%3D" withString:@"=" options:NSLiteralSearch range:NSMakeRange(0, [string length])];
[string replaceOccurrencesOfString:@"%26" withString:@"&" options:NSLiteralSearch range:NSMakeRange(0, [string length])];
[string replaceOccurrencesOfString:@"%40" withString:@"@" options:NSLiteralSearch range:NSMakeRange(0, [string length])];
[string replaceOccurrencesOfString:@"%3A" withString:@":" options:NSLiteralSearch range:NSMakeRange(0, [string length])];
[string replaceOccurrencesOfString:@"%3F" withString:@"?" options:NSLiteralSearch range:NSMakeRange(0, [string length])];
[string replaceOccurrencesOfString:@"%2F" withString:@"/" options:NSLiteralSearch range:NSMakeRange(0, [string length])];
[string replaceOccurrencesOfString:@"%3B" withString:@";" options:NSLiteralSearch range:NSMakeRange(0, [string length])];
[string replaceOccurrencesOfString:@"%25" withString:@"%" options:NSLiteralSearch range:NSMakeRange(0, [string length])];
return [NSString stringWithString: string];
}
main.m
NSString *string1 = @"<strong>strong</strong>"; NSLog(@"%@, %@, %@", string1, [string1 escapeHtml], [[string1 escapeHtml] unescapeHtml]); NSString *string2 = @"%;/=?&"; NSLog(@"%@, %@, %@", string2, [string2 urlEncode], [[string2 urlEncode] urlDecode]);
Queue.h
#import <Foundation/Foundation.h>
#define kDefaultQueueSize 20
@interface Queue : NSObject <NSFastEnumeration>
{
@private
NSMutableArray *tasks_;
int capacity_;
}
@property (nonatomic, readonly) int capacity;
- (id)init;
- (id)initWithCapacity:(int)capacity;
- (void)dealloc;
- (void)add:(id)object;
- (id)remove;
- (int)count;
@end
Queue.m
#import "Queue.h"
@implementation Queue
@synthesize capacity = capacity_;
- (id)init
{
return [self initWithCapacity:kDefaultQueueSize];
}
- (id)initWithCapacity:(int)capacity
{
if (![super init]) return nil;
capacity_ = capacity;
tasks_ = [[NSMutableArray alloc] initWithCapacity:capacity];
return self;
}
- (void)dealloc
{
[tasks_ release]; tasks_ = nil;
[super dealloc];
}
- (void)add:(id)object
{
[tasks_ addObject:object];
if ([tasks_ count] > capacity_) {
[tasks_ removeObjectAtIndex:0];
}
}
- (id)remove
{
if ([tasks_ count] < 1) return nil;
id object = [tasks_ objectAtIndex:0];
[object retain];
[tasks_ removeObjectAtIndex:0];
return [object autorelease];
}
- (int)count
{
return [tasks_ count];
}
- (NSString *)description
{
return [tasks_ description];
}
- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len
{
return [tasks_ countByEnumeratingWithState:state objects:stackbuf count:len];
}
@end
使い方
Queue *queue = [[Queue alloc] initWithCapacity:3];
[queue add:@"1"];
[queue add:@"2"];
[queue add:@"3"];
[queue add:@"4"];
[queue add:@"5"];
NSLog(@"%@, %d", queue, [queue count]);
[queue remove];
NSLog(@"%@, %d", queue, [queue count]);
for (id object in queue) {
NSLog(@"%@", object);
}
目次
間違っているかもしれないので、つっこみ大歓迎!
メモリ解放の仕組み
- alloc,initすると参照カウンタが1になる
- retain, copy すると参照カウンタが1増える
- releaseすると参照カウンタが1減る
- 参照カウンタが0になるとdeallocが呼ばれる
- allocWithZone,copyWithZone,mutableCopy,mutableCopyWithZoneも参照カウンタを1増やす
ルール
- retainはアドレスコピー
- copyは別領域にメモリを確保してコピー
- NSString,NSArray,NSDictionaryなどのMutableでないクラスはcopyしてもアドレスコピーになってしまう!
- retain, copyをした人が責任を持つ
- auto releaseをしておけば責任放棄できる
- auto releaseが設定されている変数はreleaseしてはいけない
- auto release設定した変数は予期せぬタイミングでreleaseされる可能性があるので注意!
- +で始まるメソッドはauto release設定済みなのでreleaseしてはダメ(stringWithXXXとかarrayXXX)
- NSMutableArrayなどにaddObjectした変数はreleaseしないとメモリリークする。
- initXXXメソッドは、呼び出した側がreleaseする事。(auto release設定されていない)
ハマった点
- allocの時点では参照カウンタが1にならないクラスもある(alloc,initをセットでやる事!)
- シングルトンなクラスで保持しているNSStringの変数は他のクラス内変数にしない
どうやらアドレスを共有してしまうらしく、
対象クラスのdealloc時にメモリ内容がクリアされ次にその変数を見に行く時に落ちる。
参考
http://www.textdrop.net/google-styleguide-ja/objcguide.xml
要因は沢山あると思うんだけど俺がはまったケース。
原因
という事で起きました。
調べ方
NSLog(@"%@", NSStringFromCGRect(frame));
とやると情報が見れます。
viewが表示された時点で、UITextViewにフォーカスを当てる為に、
viewDidLoadでbecomeFirstResponderをしてました。
どうやらこれが原因みたい…。
コメントアウトすると起きない…。
この警告が出る時は、動作が重くなる。
(UITextViewにフォーカスが当たってキーボードが立ち上がるまでに一瞬間がある)
標準アプリも似たような動きをしてる気がするんだよな…。
もしかして、iOSのバグ?
要追加調査。
Rubyだとstrip、PHPだとtrim
API側で削れ!!でもいいんだけど…。
Objective-Cではどうやるのか調べた
stringByTrimmingCharactersInSet
というメソッドでできる。
[str stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
とやると、空白&改行を削ってくれる。
って、メソッド名長いでしょ…。
面倒だからNSStringを拡張
#import <Foundation/Foundation.h> @interface NSString(TrimMethods) - (NSString *)trim; - (NSString *)strip; @end
#import "NSStringExtensions.h"
@implementation NSString(TrimMethods)
- (NSString *)trim
{
return [self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}
- (NSString *)strip
{
return [self trim];
}
@end
短くなった!
[str trim]; [str strip];
で使えるよ!
地点Aから見た地点Bの方位を求めたかったので、
色々調べて実装してみた。
CLLocationを拡張。
参考は、こちら
CLLocationExtensions.h
#import <Foundation/Foundation.h> #import <CoreLocation/CoreLocation.h> #import <math.h> @interface CLLocation(Extensions) - (CLLocationDirection)azimuthToLocation:(const CLLocation *)target; @end
CLLocationExtensions.m
#import "CLLocationExtensions.h"
#define kEquatorialRadius 6378137 // 赤道半径
@implementation CLLocation(Extensions)
- (CLLocationDirection)azimuthToLocation:(const CLLocation *)target
{
CLLocationDirection dx = kEquatorialRadius * (target.coordinate.latitude - self.coordinate.latitude) * cos(self.coordinate.longitude);
CLLocationDirection dy = kEquatorialRadius * (target.coordinate.longitude - self.coordinate.longitude);
return atan2(dy, dx);
}
@end
使い方
CLLocation *own = [[CLLocation alloc] initWithLatitude:緯度 longitude:経度];
CLLocation *target = [[CLLocation alloc] initWithLatitude:緯度 longitude:経度];
NSLog("[own => target] %f°", [own azimuthToLocation:target]);
みたいに使えます。
独自クラス作るより使い回しが楽そうなので、メモ。
CLLocationExtensions.h
#import <Foundation/Foundation.h> #import <CoreLocation/CoreLocation.h> @interface CLLocation (Extensions) - (CLLocationDegrees)latitude; - (CLLocationDegrees)longitude; - (BOOL)isBetterAccuracyThan:(CLLocation *)location; - (BOOL)isBetterHorizontalAccuracyThan:(CLLocation *)location; - (BOOL)isBetterVerticalAccuracyThan:(CLLocation *)location; - (NSString *)description; @end
CLLocationExtensions.m
#import "CLLocationExtensions.h"
@implementation CLLocation (Extensions)
- (CLLocationDegrees)latitude
{
return self.coordinate.latitude;
}
- (CLLocationDegrees)longitude
{
return self.coordinate.longitude;
}
- (BOOL)isBetterAccuracyThan:(CLLocation *)location
{
if (![self isBetterHorizontalAccuracyThan:location]) return NO;
if (![self isBetterVerticalAccuracyThan:location]) return NO;
return YES;
}
- (BOOL)isBetterHorizontalAccuracyThan:(CLLocation *)location
{
if (signbit(location.horizontalAccuracy)) return NO;
if (self.horizontalAccuracy <= location.horizontalAccuracy) return YES;
return NO;
}
- (BOOL)isBetterVerticalAccuracyThan:(CLLocation *)location
{
if (signbit(location.verticalAccuracy)) return NO;
if (self.verticalAccuracy <= location.verticalAccuracy) return YES;
return NO;
}
- (NSString *)description
{
return [NSString stringWithFormat:@"緯度 = %f\n経度 = %f\n高度 = %f\n精度(水平) = %f\n精度(垂直) = %f", [self latitude], [self longitude], self.altitude, self.horizontalAccuracy, self.verticalAccuracy];
}
@end

最新コメント