[iOS] Protocol – Delegateパターン | Objective-C イベント伝達 その1

2012/06/26

12/07/06 追記
delegateのコードを修正しました。
delegateはretainでなくて、assignにした方が良いみたいです。
その場合は、deallocの中のreleaseも必要なくなります。

参考
>> Why are Objective-C delegates usually given the property assign instead of retain?

AがBを作り、BのdelegateにAをセットする。
BがretainでAをもつことにより、AとBが互いにretainで参照を持つことになります。
そうなってしまうと、BをreleaseしようとしてもAをretainしているためにreleaseできずにメモリリークするということのようです。

—————-

こんにちは。きんくまです。

今回から何回かに分けて、Objective-C でのイベント伝達の扱い方について書いてみます。

まずはじめに。イベント伝達って?

イベントはいろんなものが考えられますよね。

・ユーザーがボタンを押した
・ある値になった
・タイマーが完了した
・あるView(やViewController)を破棄して、別のView(ViewController)にきりかえるタイミング

こんな感じのイベントがおこったときに、それをあるオブジェクトから別のオブジェクトに知らせたいときがあります。それをイベント伝達とします。

今あるオブジェクトから別のオブジェクトへ伝えると書いたのですが、伝えられる先の数も2種類考えられます。

・1対1
・1対多(複数)

では具体的にはどうやってイベントを伝えるのでしょうか?

Objective-Cの3つのイベント伝達の仕組み

Objective-Cにはイベント伝達の仕組みが大きく分けて3つ用意されています。

・Protocol – Delegateパターン
・KVO (Key-Value Observing)
・NSNotification

それぞれに長所と短所があります。なので、目的に合わせて使用するのが良いと思います。
その比較については、それぞれの実装方法を書いたあとにまとめとしてやりたいと思います。

今回は、Protocol – Delegateパターンについて書きます。

Protocol – Delegateパターン

聞いたことのない人は何か新しいもののような気がするのですが、
UIKitを使っている人はたぶん既に一度は使っていると思います。

例えば、UITableViewDelegate, UITableViewDataSource, UIScrollViewDelegate などです。
UIScrollViewDelegateだったら、

– (void)scrollViewDidScroll:(UIScrollView *)scrollView
– (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView

などのメソッドを使ったことがあるんじゃないでしょうか。

使い方は

1. delegateプロパティにオブジェクトの参照を代入
2. オブジェクトのinterfaceのクラス名の後ろに<Protocol名> と追記 -> MyClass:NSObject<MyProtocol> みたいな
3. Protocolに宣言されているメソッドを実装部(.m)に書く

という感じです。

こういったProtocol -DelegateパターンはUIKitだから特別できるというのではなく、
Objective-Cのそもそもの機能を利用しています。
なので、自作することが可能です。

今のは使う側であり、通知される側ということになります。

では通知する側はどうすればよいのでしょうか。

Protocol – Delegateパターンの作り方

1. Protocolを定義する
2. 通知する側にインスタンス変数とプロパティでdelegateを用意
3. 通知したいイベントが発生したタイミングで、delegateのProtocolに定義されたメソッドを呼び出す

という感じになります。
実際に作ってみましょう。今回作成するのはこんな感じのものです。

window.rootViewController直下にKKViewControllerというものがあり、
その中にカスタムビューのKKCountPushView(緑の背景部分)というものがあります。

protocol_delegate_fig1

KKCountPushViewの中にはボタンがあり、押すたびに上のラベルに押した回数が表示されます。
現時点では、親のKKViewControllerと子供のKKCountPushViewには、イベント伝達の関係はありません。
子供のボタンの押した回数が変更した際に、親に伝達するようにこれから順番に実装していきます。

現時点のコードです。ここは大事なところでないので、飛ばしても大丈夫です。

KKCountPushView.h

#import <UIKit/UIKit.h>

@interface KKCountPushView : UIView
{
    int _pushCount;
    UIButton *_pushButton;
    UILabel *_countLabel;
}

@end

KKCountPushView.m


#import "KKCountPushView.h"

@interface KKCountPushView()
- (void)updateCountLabel:(int)count;
- (void)pushButtonTapped;
@end

@implementation KKCountPushView

- (void)dealloc
{
    [_pushButton release];
    [_countLabel release];
    [super dealloc];
}

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {

        self.backgroundColor = [UIColor colorWithRed:210/255.0 green:231/255.0 blue:159/255.0 alpha:1.0];

        _pushCount = 0;
        
        //button
        _pushButton = [[UIButton buttonWithType:UIButtonTypeRoundedRect] retain];
        _pushButton.frame = CGRectMake((220 - 100) * 0.5, 70, 100, 40);
        [_pushButton setTitle:@"PUSH ME" forState:UIControlStateNormal];
        [_pushButton addTarget:self action:@selector(pushButtonTapped) forControlEvents:UIControlEventTouchUpInside];
        [self addSubview:_pushButton];
        
        //label
        _countLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 30, 220, 20)];
        _countLabel.backgroundColor = [UIColor clearColor];
        [_countLabel setTextAlignment:UITextAlignmentCenter];
        [self addSubview:_countLabel];
        [self updateCountLabel:_pushCount];
    }
    return self;
}

- (void)updateCountLabel:(int)count
{
    _countLabel.text = [NSString stringWithFormat:@"%d times pushed", count];
}

- (void)pushButtonTapped
{
    _pushCount++;
    [self updateCountLabel:_pushCount];
}

@end

KKViewController.h

#import <UIKit/UIKit.h>

@class KKCountPushView;

@interface KKViewController : UIViewController
{
    KKCountPushView *_countPushView;
    UITextView *_logView;
}

@end

KKViewController.m

#import "KKViewController.h"
#import "KKCountPushView.h"

@interface KKViewController ()
- (void)log:(NSString *)logText;
@end

@implementation KKViewController

- (void)dealloc
{
    [_countPushView release];
    [_logView release];
    [super dealloc];
}

- (void)loadView
{
    [super loadView];
    UIView *myView = [[UIView alloc] init];
    myView.backgroundColor = [UIColor whiteColor];

    _countPushView = [[KKCountPushView alloc] initWithFrame:CGRectMake(50, 50, 220, 140)];
    [myView addSubview:_countPushView];

    _logView = [[UITextView alloc] initWithFrame:CGRectMake(0, 240, 320, 240)];
    _logView.editable = NO;
    [myView addSubview:_logView];

    self.view = myView;
    [myView release];
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self log:@"Hello"];
    [self log:@"Protocol - Delegate"];
}

- (void)log:(NSString *)logText
{
    NSString *newLog = [NSString stringWithFormat:@"%@\n%@", _logView.text, logText];
    _logView.text = newLog;
}

@end

1. Protocolを定義する

Protocolを定義します。
Protocolは、ヘッダーファイルとして独立して書いてもよいですし、
どこか別のヘッダーファイルに一緒に書いてもよいです。

複数にまたがるときは独立して書いた方がよいと思いますが、
今回はKKCountPushView.hだけが使うProtocolということで、KKCountPushView.hに足すことにします。

@class KKCountPushView;

@protocol KKCountPushViewDelegate <NSObject>
@optional 
- (void)countPushView:(KKCountPushView *)countPushView countChange:(int)pushCount;
@end

プロトコルのメソッドは好きな数定義することが可能です。
また、何を引数にしてイベント伝達にするかも自分で決められます。
どんなものが使いやすいかは、UIKitの各Delegateを参考にしてみるとよいかもしれません。
今回は、押した回数を引数に通知するようにしました。

また必ずしも実装しなくてよいメソッドは、@optional の下にまとめて書いておきましょう。

2. 通知する側にインスタンス変数とプロパティでdelegateを用意

KKCountPushViewにDelegateを追加します。変更がなかったその他のメソッドは省略します。

KKCountPushView.h

@interface KKCountPushView : UIView
{
    int _pushCount;
    UIButton *_pushButton;
    UILabel *_countLabel;
    id<KKCountPushViewDelegate> _delegate; //追加
}
@property (nonatomic, assign) id<KKCountPushViewDelegate> delegate; //追加

@end

KKCountPushView.m

@implementation KKCountPushView
@synthesize delegate = _delegate; //追加

- (void)dealloc
{
    [_pushButton release];
    [_countLabel release];
    [super dealloc];
}

3. 通知したいイベントが発生したタイミングで、delegateのProtocolに定義されたメソッドを呼び出す

ボタンを押した際にdelegateのメソッドを呼び出します。
_delegateがnilかどうかは、判定しなくても大丈夫です。
nilのメソッドを読んでもObjective-Cはnilを返すだけなので。

KKCountPushView.m

- (void)pushButtonTapped
{
    _pushCount++;
    [self updateCountLabel:_pushCount];

    //追加
    if ([_delegate respondsToSelector:@selector(countPushView:countChange:)]){
        [_delegate countPushView:self countChange:_pushCount];
    }
}

これで準備が整いました。早速親のKKViewControllerから使ってみます。

使ってみる

KKViewController.h

#import <UIKit/UIKit.h>
#import "KKCountPushView.h"

//クラス名の後ろにProtocolを追加している
@interface KKViewController : UIViewController<KKCountPushViewDelegate>
{
    KKCountPushView *_countPushView;
    UITextView *_logView;
}

@end

KKViewController.m

- (void)loadView
{
    [super loadView];

//省略

    _countPushView = [[KKCountPushView alloc] initWithFrame:CGRectMake(50, 50, 220, 140)];
    _countPushView.delegate = self; //追加
    [myView addSubview:_countPushView];

//省略
}

//Protocolメソッドを追加
- (void)countPushView:(KKCountPushView *)countPushView countChange:(int)pushCount
{
    [self log:[NSString stringWithFormat:@"count change : %d", pushCount]];
}

これで完成です。実際に動かすとこうなります。

protocol_delegate_fig2

Protocolを定義するとどういいんでしょ?

Protocolを定義しないでも、呼ぶ側が呼ばれる側のインスタンスを直接持って、呼ばれる側のメソッドを直接呼ぶことが可能です。
じゃあ、なんでこんなまわりくどいことをするんでしょうか?

答えは、それをすることで呼ぶ側と呼ばれる側の関係が疎結合になるからです。
つまり呼ばれる側はProtocolを実装さえしてれば誰でも構わないということになります。
今回作ったKKPushViewは、必要であれば別のところにそのまま持っていって使い回すことが可能になります。

このなるべく関係を薄くすることで、他のところでも使い回すことが可能になるというのは、結構大事なことかなと思ってたりします。

今回のプロジェクトデータ一式です。

※ 2012/07/22 コード修正しました
>> プロジェクトデータ一式

LINEで送る
Pocket

[iOS] Objective-C @propertyについて

2012/06/25

こんにちは。きんくまです。
今回はObjective-Cの@propertyについてのまとめです。
ARCは使ってないバージョンです。

公式のリファレンスです。
>> Declared Properties

Obj-Cをはじめた当初はよくわからないながらも何となく使っていたのですが、
いろいろとわかってきたのでまとめておこうと思いました。

@propertyはカタカナに直すとプロパティだから、別言語から来た人(私)は
何か実体のあるもののような気がするのですが、そうではなくて
実際はアクセサメソッド(getter, setter)のことです。

なので、クラス外からアクセスするときに必要に応じて定義するとよいです。
最初私はよくわからず、インスタンス変数に全てプロパティを定義していたのはナイショです。

@propertyを使わないでインスタンス変数にアクセス = KVC

ではまずは@propertyを使わないでインスタンス変数にアクセスしてみましょう。
こんな感じのクラスがあるとします。

@interface Person : NSObject
{
    NSString *_firstName;
    NSString *_lastName;
    int _age;
}
@end

@implementation Person
- (void)dealloc
{
    [_firstName release];
    [_lastName release];
    [super dealloc];
}
@end

これにアクセスするのに、Objective-Cに用意されている KVC(Key-value coding)という仕組みを利用します。

int main(int argc, const char * argv[])
{

    @autoreleasepool {
        Person *person1 = [[Person alloc] init];

        [person1 setValue:@"Taro" forKey:@"_firstName"]; //KVC

        NSString *name1 = [person1 valueForKey:@"_firstName"]; //KVC

        NSLog(@"name1 = %@", name1);
        [person1 release];        
    }
    return 0;
}

setValue:forKey で値代入(setter)。 valueForKey で値取得(getter)。することができます。

@propertyを定義

KVCでもアクセスできたのですが、毎回書くには長いです。
なので@propertyを使ってみます。その場合、定義する方は長くなるのですが、使う方は短くなります。

@interface Person : NSObject
{
    NSString *_firstName;
    NSString *_lastName;
    int _age;
}

@property (nonatomic, retain) NSString *firstName;
@property (nonatomic, retain) NSString *lastName;
@property (nonatomic, assign) int age;

@end

@implementation Person

@synthesize firstName = _firstName;
@synthesize lastName = _lastName;
@synthesize age = _age;

- (void)dealloc
{
    [_firstName release];
    [_lastName release];
    [super dealloc];
}
@end

@interfaceのクラス定義のところで@propertyを書く。
@implementationのクラス実装のところで@synthesizeを書く。
というふうにやります。

@synthesize

実装ファイルのところで@synthesizeをこう書きました。

@synthesize firstName = _firstName;

私の場合はインスタンス変数とプロパティを明確に区別するために

・インスタンス変数は 「_」アンダースコアを変数名の最初につける
・プロパティには「_」をつけない

とそれぞれ別の名前で書いているので、プロパティとインスタンス変数をひもづけるために上の書き方になります。

もし、インスタンス変数とプロパティが同じ名前だったら

@synthesize firstName;

とするだけでよいです。

Attributes 属性

@propertyの後にあるnonatomic, retain, assignというのがあります。
これは補助情報というか属性というかそんなものです。

私の覚え方としてはこんな感じです。

Attributes 説明
nonatomic スレッド使わないときはこっちを使う
atomic スレッド使うときはこっちを使う。(使ったことないです、、。)
retain setterのとき、代入する対象がNSObjectの子供だったらこっち
assign setterのとき、代入する対象がプリミティブ(int, float, charとかNSObjectの子供じゃない)だったらこっち
readonly 読み込み専用

@propertyを使ってアクセス

「.」ドット を使って書くことができます。KVCよりもすっきりかけました。

int main(int argc, const char * argv[])
{

    @autoreleasepool {
        
        Person *person1 = [[Person alloc] init];
        person1.firstName = @"Taro";
        person1.lastName = @"Yamada";
        person1.age = 45;
        NSLog(@"%@ %@ is age %d", person1.firstName, person1.lastName, person1.age);
        [person1 release];
        
    }
    return 0;
}

@synthesizeの中身

@synthesizeは実際にどういうことをやるものなのかというと、
コンパイラが後から自動で実際のメソッドを付け足してくれるものです。

こちらで詳しい解説されてます。
>> Objective-Cの @property と @synthesize の組み合わせが何をやっているのかを解説 – 強火で進め

今回の場合だと実装部分にこんなのが足されます。
getterはプロパティと同じ名前の、setterは「set+プロパティ名」のメソッドになります。

- (NSString *)firstName
{
    return _firstName;
}

- (void)setFirstName:(NSString *)firstName
{
    [_firstName release];
    _firstName = [firstName retain];
}

- (NSString *)lastName
{
    return _lastName;
}

- (void)setLastName:(NSString *)lastName
{
    [_lastName release];
    _lastName = [lastName retain];
}

- (int)age
{
    return _age;
}

- (void)setAge:(int)age
{
    _age = age;
}

@propertyはメソッドなので、必ずインスタンス変数に1対1対応していなくてもよい

@propertyはメソッドなので、必ずインスタンス変数に1対1対応していなくてもよいです。
例えば、今回の例に fullName をつけたしてみるとこうなります。


#import <Foundation/Foundation.h>

@interface Person : NSObject
{
    NSString *_firstName;
    NSString *_lastName;
    int _age;
}

@property (nonatomic, retain) NSString *firstName;
@property (nonatomic, retain) NSString *lastName;
@property (nonatomic, readonly) NSString *fullName;  //追加
@property (nonatomic, assign) int age;

@end

@implementation Person

@synthesize firstName = _firstName;
@synthesize lastName = _lastName;
@synthesize age = _age;
@synthesize fullName; //追加

- (void)dealloc
{
    [_firstName release];
    [_lastName release];
    [super dealloc];
}

 //追加
- (NSString *)fullName
{
    return [NSString stringWithFormat:@"%@ %@", _firstName, _lastName];
}

@end

int main(int argc, const char * argv[])
{

    @autoreleasepool {
        
        Person *person1 = [[Person alloc] init];
        person1.firstName = @"Taro";
        person1.lastName = @"Yamada";
        NSLog(@"fullName is %@", person1.fullName);  //追加
        [person1 release];
        
    }
    return 0;
}
LINEで送る
Pocket

[iOS] AppCodeは良いエディタ

2012/06/21

こんにちは。きんくまです。

この1ヶ月ほどiOSアプリと平行して、久しぶりにFlash案件をやっていたのですが、
Objective-Cと比べて、短いコードで同じようなことができる、あの手軽さはやはり良いものですね。
アニメーションを使ったページも、スクリプトとタイムラインを上手に組み合わせられて◎です。

さて、AppCodeです。
>> AppCode

前回記事にしてから、実際にずっと使ってました。
その感想などを書こうと思います。

最初に結論から書くと、良いツールなので買うと思います。
まだ使用期限がきてないから買ってないけど、期限きたら買うつもりです。

AppCodeはXcodeと併用して使うもの

使う前は、AppCodeはXcodeを置き換えるものだと思っていました。
ところが、これが勘違いだとわかりました。
AppCodeはコーディングを助けてくれるエディタです。

Xcode > xib, CoreDataの.xcdatamodeld, Info.plist などを担当
AppCode > .h, .m, .mm などのコーディング全般担当

そんな感じです。もちろんAppCodeだけ立ち上げて作業ということも可能です。

もしAppCodeとXcodeを同時に開いていて、片方でコードを編集してアプリを切り替えた場合は、
もう片方にもすぐに反映されるという感じです。
ただ、Xcodeでファイルを追加したりすると、AppCodeは一度プロジェクトを読み込み直します。
ファイルの中身を編集するだけだとそういうことはほとんどおきません。

では、実際にどんなところがAppCodeの嬉しい機能かといいますと、以下のようになります。

ヘッダファイルの自動インポート、ヘッダファイルの自動整理

コーディング中に、新しいクラスを使おうとしたときに、使うヘッダファイルを実装ファイルの
上の方にいって書き足す作業がどうにも面倒でした。
Eclipseとかは当たり前にできるヘッダファイルの自動インポートが、AppCodeでもできるようになります。
コマンドだけでやってくれるので楽です。

書いているときに自動挿入されますし、インポート忘れの場合、こんな感じに警告がでます。

appcode_fig1

Option + Enterを押すと、警告が消えてヘッダファイルが自動挿入されます。

appcode_fig2

あとは、不要なヘッダファイルはヘッダファイルのところで、ポップアップメニューから
Optimize Importsとすると自動整理されて削除されます。

インスタンス変数のプロパティ化

インスタンス変数のプロパティ化も自動でやってくれます。

@interface SampleObj:NSObject{
    NSArray *_sampleArray; //これをプロパティ化したい
}

Cmd + N からPropertiesを選択して出てくるダイアログでプロパティ化したいインスタンス変数を選択すると、

SampleObj.h

@interface SampleObj:NSObject{
    NSArray *_sampleArray;
}
@property(nonatomic, retain) NSArray *sampleArray; //自動生成

SampleObj.m

@implementation SampleObj
@synthesize sampleArray = _sampleArray; //自動生成
- (void)dealloc
{
    [_sampleArray release];  //自動生成
    [super dealloc];
}
@end

こんな感じに、@synthesizeしつつ、deallocの中にも書いてくれます。これは嬉しいポイント!

プロパティ、メソッド一覧 – Structure

プロパティ、メソッド一覧が常に表示されるStructureパネルがあります。
Xcodeにもあるのですが、プルダウンから選ぶ形式のため毎回プルダウンを押す必要があります。
Structureパネルで目的のメソッド押せば、コードのカーソル位置を自動できりかえたり、
逆にコードのカーソル位置によって、Structureのどこかを表示したりできます。

appcode_fig3

メソッド呼び出しもと一覧

このメソッドを呼び出しているのがどこからなのかを一覧でみることができます。

appcode_fig4

知りたいメソッドにカーソルを置いてから、メニューのNavigate > Call Hierarchyを選択すると、上のパネルがでてきます。
パネル内の呼び出しメソッドを選択すると、コード編集画面が自動できりかわります。
また、その呼び出しメソッド自身もどこから呼ばれているかを再帰的に見ることもできます。

「これを変更したら、どこに影響があるんだっけ?」とか、「呼び出し順序を知りたい」なんてときにかなり便利です。
個人的にはけっこう助けられました。

まとめ

その他にも、メモリリークや文法上のエラーをすぐ指摘してくれたり、コード補完が賢かったりするのも良いポイントです。
個人のディベロッパーは$99です。
趣味でやるにはちと高いけど、仕事でやるにはそんなもんかなとおもってます。

Objective-cはどうしてもコードを書く量が多くなってしまうので、(しかも縦にも横にも)
ソースを読むときに移動に時間がかかり、個人的には気力が消耗しやすい言語だと思ってマス。
(ただその仕様上、コメントなしでも何をしているのかはソースを見るだけでわかりやすい)
こういうツールを使ってそういうメンドクサイ感を減らして、やる気にさせるのは良いかなと思います。

LINEで送る
Pocket

[iOS] AppCode アンチエイリアスを切る設定

2012/06/3

こんにちは。きんくまです。

AppCodeというアプリがあるみたいです。
iOSアプリの開発ができるエディタらしいのです。
どうやらAS3を書いていたときに、FlashDevelopに出会ったみたいなそんな感じらしいのです。

詳しい機能の解説はこちらです。
>> XCodeからappCodeへ乗り換える8つの理由 2011-12-11 – 人工無脳が作りたい

これは、ニヤニヤものの機能じゃマイですか、、。
特に、上のサイトで解説されている機能として個人的にニヤニヤものは。

・インスタンス変数を簡単にプロパティに出来る
・「メソッドに引数を一つ足すだけなのに、どうしてこんな苦労をしなくちゃいけないんだ…」と思ったことはありませんか?appCodeならGUIで引数を追加してボタンを一つ押すだけです。
・Structureウィンドウ

です。これは試してみるしかない。30日間なら無料だし。
あと心配なのがXcodeとの住み分け。そしたら公式のページに完全に互換性あるから心配ないっすよ。
と書いてありました。

AppCode is fully compatible with Xcode (up to v.4.4). 
You can open existing Xcode projects and work on a project in both IDEs in parallel. 
No additional configuration needed and your projects stay always 100% Xcode-compatible.

あとより詳しい比較をやっているページ
>> Xcode vs. AppCode

んで早速ダウンロードしてきまして。
まずフォント設定をしてしまう私です。

アンチなしが好きなので、AppCodeでもアンチなしにしたい。
(ちなみにフォントはAndale Monoが好きです)

設定はパネルからできました。
Settings > Editor > Appearance > Use anti-aliased font

appcode_anit-aliased

他のエディタみたいにTerminalから
defaults write com.jetbrains.AppCode AppleAntiAliasingThreshold 24
みたいなコマンドを打って「変わらないじゃん !」とか言ったのはナイショです。

LINEで送る
Pocket

[iOS] フォント名一覧を出力するスニペット

2012/05/27

個人的メモです。for in 使ってるんでソートされてないです。
ソートしたい場合は、インクリメント使うとよろし。
OSのバージョンにより、使えるフォントが違うのかもしれないので、
あやしいときは、実際に実行してみてリストを吐き出すのが確実です。

    NSArray *familyNames = [UIFont familyNames];
    NSString *familyName;
    for(familyName in familyNames){
        NSLog(@"---  family name: %@", familyName);
        NSArray *fontNames = [UIFont fontNamesForFamilyName:familyName];
        NSString *fontName;
        for(fontName in fontNames){
            NSLog(@"  font name: %@", fontName);
        }
    }

フォントファミリーは大まかなフォントの種類で、フォント名がUIFontに指定できる方です。

ファミリー フォント名
Hiragino Kaku Gothic ProN HiraKakuProN-W3
HiraKakuProN-W6
Helvetica Helvetica
Helvetica-Oblique
Helvetica-Light
Helvetica-LightOblique
Helvetica-Bold
Helvetica-BoldOblique
LINEで送る
Pocket

[Fireworks] HTMLコーディングに便利な、スライス画像のスニペットを書き出すFireworks拡張機能を作りました

2012/05/23

こんにちは。きんくまです。

HTMLコーディングに便利な、スライス画像のスニペットを書き出すFireworks拡張機能を作りました。
タイトル長いです、、。


12/05/27更新
githubにソースコードをアップしました。
https://github.com/KinkumaDesign/ImageSnippet

スクリーンショット

image_snippet2

使い方

例1 )
こんな感じのスライスがあったとします。

image_snippet1

このスライスを選択します。(複数には対応していないので、1つだけ選択します)

それで、パネルの挿入ボタンを押すと下記のようにスニペットエリアに、スライスの情報を反映させたコードが吐き出されます。

image_snippet3

この吐き出されるコードは、上のフォーマット設定エリアに書いてある文字列の中で、
該当部分が置換されて出てきています。

今回のフォーマットのテキストはこんな感じです。

<img width="%w" height="%h" src="images/%p" alt="">

%w, %h, %p などの文字列が入っています。これがスライスの名前や幅、高さに変更されます。

取得できる値は次の5つです。

フォーマット スライスの値
%p 名前
%w
%h 高さ
%x x
%y y

フォーマットはタブを切り替えることで、6つまで設定することが可能です。

例2)
CSSを書いているときに、画像のwidth,heightを目視で調べて、
またエディタに戻って打ち込んで、、、という作業は続けているとすごく疲れます。
そんなときに、こんなフォーマットを書いておきます。

width:%wpx;
height:%hpx;
left:%xpx;
top:%ypx;

それで、またスライスを選択して、挿入ボタンを押すとこんなコードが吐き出されます。

width:99px;
height:95px;
left:47px;
top:60px;

あとは、挿入ボタンのとなりのクリップボードボタンを押して、クリップボードに転送して、
好きなエディタに戻ってコピペすれば楽ちんです。

フォーマットには好きな文字列をいれることが可能なので、案件や普段使っている書き方を
書いておくと良いと思います。

また、スニペットエリアは挿入ボタンを押すたびにテキストが追加されていくので、
ある程度画像情報をまとめて吐き出した後、コピペしてコーディング用のアプリにもっていくのが
効率がいいと思います。

利点

・アプリケーションを頻繁に行き来する必要がない。
・コーディングエディタ(DWとか)で、画像を開くダイアログを出して、目視でファイル名を確認して、、、という作業が不要になるので、目が疲れない
・幅、高さなどを目で追う必要がないので、目が疲れない

開発の経緯

これのもととなるもの自体は2〜3年前に作って当時かなり使用していました。
コーディングの速度が早くなって、便利だなーと思ってました。
ただ、それがあまりに個人使用だったので、もう少し汎用性のあるものを作りたいなと思ってました。
でも自分は最近はHTMLコーディングはメインでしていないので、使う機会が減っていた状態でした。
前に作ったFWの拡張機能たちが、なんやかんやと好評で細々と使われているようなので、これはぜひ作りたいと思い、作った次第です。

インストール方法

1) データをダウンロードします。
>> ImageSnippet

2) 該当パスにコピーします
Macだったらこんな感じ。

/Applications/Adobe Fireworks CS5.1/Configuration/Command Panels/KinkumaUtility/ImageSnippet.swf
/Applications/Adobe Fireworks CS5.1/Configuration/Command Panels/KinkumaUtility/jsf/ImageSnippet.jsf

Winな人は同じようなパスがあると思います。Program Files以下だったかも

3) Fireworksを立ち上げ直します

4) メニューのWindow > KinkumaUtility > ImageSnippet
を選択するとパネルが出てきます

5) あとは使い方の説明通りです

LINEで送る
Pocket

[iOS] NSFetchRequest:initWithEntityNameをiOS4で使おうとしてエラー

2012/05/18

CoreDataのメモです。同じエラーにあった人向けです。

NSFetchRequestで、データが空(まだ1つもデータが入っていない)のEntityをひっぱってこようとしたら、こんな感じのエラーが出ました。

reason: 'This fetch request xxxxx was created with a string name (Entityの名前), and cannot respond to -entity until used by an NSManagedObjectContext'

そんでググったところ、同じところで詰まっている人がいたです。

>> NSFetchRequest Problem Under iOS 4.3.5

結論としては、
・エラーが出ているのは空のデータを取得しているからではない
・NSFetchRequest: initWithEntityNameはiOS5からのAPIなので、
 iOS4では以下のようにNSEntityDescriptionを使えば大丈夫

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"MyEntity" inManagedObjectContext:context];
[fetchRequest setEntity:entity];

コード修正したら動いた!

最初、空データのところとか、NSFetchedResultsControllerをその後で使っているからとか、色々と原因を考えたけど、APIのバージョンが対応してないだけっていうオチでした、。テヘぺろ。

Daveさんありがとう。

LINEで送る
Pocket

ページトップへ戻る