2010-12-15 10 views
0

= MXテーブルビューyはMXの例を=私はyの関数のために2列(xとy)とテーブルビューを作成する方法を

アイブ氏は完全な失敗に終わるすべてのそれらのものの多くを、試してみました。

サンプルコードを作成して説明できますか?

私は、Boolのチュートリアルのすべての種類、内容のコピーと貼り付け方法、ファイルへの保存方法、開いているアプリケーションのリストの作成方法などを教えてくれました。彼らは

過度に複雑であるため、私はここから行くんこの

//array.m 

    #import "array.h" 

    @implementation array 

    - (IBAction)makeArrays:(id)sender 
{ 
    int x,y; 
    NSNumber *multiplier=[NSNumber numberWithFloat:[mField floatValue]]; 

    for (x=0;x++;x<181) 
    { 
     y=[multiplier floatValue]*x; 

     NSNumber *xValue = [NSNumber numberWithInt:x]; 
     NSNumber *yValue = [NSNumber numberWithInt:x]; 

    NSArray *xArray = [NSArray arrayWithObject:xValue]; 
    NSArray *yArray = [NSArray arrayWithObject:yValue]; 
    } 
} 

@end 

とクラスファイル

//array.h 

#import <Cocoa/Cocoa.h> 

@interface array : NSObject { 
IBOutlet id mField; 
} 
- (IBAction)makeArrays:(id)sender; 

@end 

がありますか?

+0

'makeArrays'のように、' NSNumber'と 'float'の間で切り替えを行う必要はありません。 – outis

答えて

1

まずOOPで行うべきことは、オブジェクトのクラスを検討することです。 CocoaはMVC(Model、View、Controller)アーキテクチャを使用しているため、クラスはこれらの3つのカテゴリのいずれかに収まる必要があります。 CocoaはすでにNSTableViewクラスを提供していますので、モデルとコントローラを残すことができます。

あなたが取ることができるモデルクラスに多くの異なるアプローチがあります。

  • あなたは
  • 別々の配列で、xとyの値を保持している関数テーブルクラスを書くことができますが、関数テーブルを書くことができます(x、y)のペアの単一の配列を持つクラスです。
    • この実装または以前の実装では、両方のアレンジメントをサポートするパブリックインターフェイスを提供することができます(つまり、与えられたxとx、yおよび(x、y)コレクション)。いくつかの実装の詳細は、テーブルビューをデータ(バインディング、または古いNSTableViewDataSource protocol)にどのように接続するかによって異なります。
  • x値の配列を使用して、value transformerを作成することもできます。このアプローチでは、y値はモデルではなくテーブルビューに存在します。
  • そしてそう

上のアプリケーションの要件を取るためにどのアプローチを決定します。最小限のコードしか必要としないため、バリュートランスの手法を紹介します。

コントローラの場合は、NSArrayController(NSTableViewで非常にうまくいく)に依存することも、自分でNSArrayControllerを作成することもできます。たとえば、NSMutableArrayをモデルとして使用し、配列の値を他の値にマップするコントローラを作成できます。このコントローラーは、定義したブロックまたは一部の関数クラスを使用してマッピングを実行できます。

ご覧のとおり、いくつかのオプションがあります。最小のコーディングを必要とするオプション、つまり、値トランスフォーマ、コントローラ用のNSArrayController、モデル用のNSMutableArray(値トランスフォーマも格納されたオブジェクトに格納されている)を使用します。以下では、コードは標準的な規則に従ってファイルに保存する必要があります。各インタフェースと実装は、クラスと同じ名前の別ファイルにあり、インタフェースの場合は ".h"、実装の場合は ".m"の拡張です。また、Cocoa/Cocoa.hや各クラス実装の独自のインターフェイスなど、共通のインポートステートメントについても気にしません。

まず、バリュートランスフォーマです。実際には抽象スーパークラスと具象サブクラスの2つがあります。この分離は、後で簡単に他の関数タイプを追加することができます。スーパークラスFunctionTransformerは非常に簡単です。その基部からオーバーライドする必要があるすべて、NSValueTransformer、変換された値のクラスを返すメソッドである、transformedValueClasstransformedValue:

@interface FunctionTransformer : NSValueTransformer 
+ (Class)transformedValueClass; 
@end 

@implementation Function 
+ (Class)transformedValueClass { 
    return [NSNumber class]; 
} 
@end 

コンクリートサブクラス、LinearTransformerは、値の変圧器の一次メソッドをオーバーライドする必要があります。線形変換は可逆であるため、reverseTransformedValue:も提供します。また、傾きと切片の値のプロパティも必要です。

#import "FunctionTransformer.h" 

@interface LinearTransformer : FunctionTransformer { 
    NSNumber *m_; 
    NSNumber *b_; 
} 
@property (nonatomic,retain) NSNumber *slope; 
@property (nonatomic,retain) NSNumber *intercept; 


+ (BOOL)allowsReverseTransformation; 

-(id)init; 
-(id)initWithSlope:(float)slope; 
-(id)initWithIntercept:(float)intercept; 
-(id)initWithSlope:(float)slope intercept:(float)intercept; 

-(void)dealloc; 

-(NSNumber*)transformedValue:(id)value; 
-(NSNumber*)reverseTransformedValue:(id)value; 
@end 


@implementation LinearTransformer 
@synthesize slope=m_, intercept=b_; 

+(BOOL)allowsReverseTransformation { 
    return YES; 
} 
-(id)initWithSlope:(float)m intercept:(float)b { 
    if ((self = [super init])) { 
     m_ = [[NSNumber alloc] initWithFloat:m]; 
     b_ = [[NSNumber alloc] initWithFloat:b]; 
    } 
    return self;  
} 

-(id)init { 
    return [self initWithSlope:1.0 intercept:0.0]; 
} 
-(id)initWithSlope:(float)slope { 
    return [self initWithSlope:slope intercept:0.0]; 
} 
-(id)initWithIntercept:(float)intercept { 
    return [self initWithSlope:1.0 intercept:intercept];  
} 


-(void)dealloc { 
    [b release]; 
    [m release]; 
    [super dealloc]; 
} 


-(NSNumber*)transformedValue:(id)value { 
    return [NSNumber numberWithFloat:([value floatValue] * [m floatValue] + [b floatValue])]; 
} 

-(NSNumber*)reverseTransformedValue:(id)value { 
    return [NSNumber numberWithFloat:(([value floatValue] - [b floatValue])/[m floatValue])]; 
} 
@end 

あなたが傾きと切片を設定することができるように使用されるように登録する必要がLinearTransformer特定。アプリケーションデリゲートはこのトランスフォーマーを(x値のコレクションと共に)所有することも、カスタムコントローラーを作成することもできます。私たちはx値と値トランスフォーマーを束ねたモデルクラスを書くつもりです。名前はFunctionTableです。ファンクション・トランスを設定するには、トランスをバリュー・トランスとして登録するサブタスクが必要です(+setValueTransformer:forName:を使用)。これは、関数トランスフォーマープロパティ(f)に独自のセッター(setF:)を提供する必要があることを意味します。デフォルトでは

#import "FunctionTransformer.h" 

extern NSString* const kFunctionTransformer; 

@interface FunctionTable : NSObject { 
    NSMutableArray *xs; 
    FunctionTransformer *f; 
} 
@property (nonatomic,retain) IBOutlet NSMutableArray *xs; 
@property (nonatomic,retain) IBOutlet FunctionTransformer *f; 
@end 

// FunctionTable.m: 
#import "LinearTransformer.h" 

NSString* const kFunctionTransformer = @"Function Transformer"; 

@implementation FunctionTable 
@synthesize xs, f; 

-(id) init { 
    if ((self = [super init])) { 
     xs = [[NSMutableArray alloc] init]; 
     self.f = [[LinearTransformer alloc] init]; 
     [f release]; 
    } 
    return self; 
} 
-(void)dealloc { 
    [f release]; 
    [xs release]; 
    [super dealloc]; 
} 

-(void)setF:(FunctionTransformer *)func { 
    if (func != f) { 
     [f release]; 
     f = [func retain]; 
     [NSValueTransformer setValueTransformer:f forName:kFunctionTransformer]; 
    } 
} 
@end 

FunctionTableLinearTransformerを使用しています。別のものを使用する場合は、FunctionTablesfプロパティを設定するだけです。 Interface Builder (IB) by using bindingsでこれを行うことができます。この単純化された実装では、値トランスフォーマーは常に "Function Transformer"という名前で登録され、実際にはFunctionTableに制限されています。より複雑なスキームは、を登録するときに使用される固有の変圧器名をすべてFunctionTableに与えることです。すべてを設定するには

  1. は、IBにおけるアプリケーションのメインウィンドウのペン先を開きます。
  2. NSArrayControllerとFunctionTable(およびもしあればカスタムアプリケーションデリゲート)をインスタンス化します。メインウィンドウに
  3. 、追加:要素を追加および削除する
    1. ボタン、
    2. 傾きと切片のラベルとNSTextFields、
    3. NSTableViewを。 「X」と「Y」(アプリが動作するために必要ではない)
    4. connectionsを設定するには、テーブルヘッダーを設定
    • は追加&をお持ちのボタンがNSArrayControllerはのadd:に送る削除し、 remove:アクション。
    • NSTextFieldsの値をFunctionTablesのf.slopef.interceptのキーパスにバインドします。
    • NSTableViewの両方の列の値をFunctionTablesのxsにバインドします。
    • 第2列の値トランスフォーマーを「機能トランスフォーマー」に設定する
    • NSArrayControllerのコンテンツ配列をFunctionTableのxsキーにバインドします。
    • アプリデリゲートがある場合は、File's Ownerのdelegate店舗に接続します。

ビルドして実行します。追加ボタンと削除ボタンを使用して、テーブルへの行の追加と削除を行うことができます。行の "x"と "y"列を編集することができます(後者はreverseTransformedValue:のおかげです)。 「x」または「y」のいずれかの列で並べ替えることができます。スロープとインターセプトを変更することはできますが、行を個別に選択しない限り、表内の更新を気付かないでしょう。

高度なトピック

テーブルビュー更新問題を解決するために、我々は別の上の変化への1つのオブジェクトの(FunctionTransformer)プロパティ(FunctionTable)特性に変更を伝播する必要があります。関数トランスのプロパティがFunctionTableobserveに変更され、FunctionTableにそのようなプロパティが変更されたことが通知されると、xsプロパティが変更されたことを通知します(これは少し悪いです.hasn '実際に変更されました)。これは少し魔法のようになるので、私と一緒に熊。

オブジェクトは、他のオブジェクトのKVOメソッドaddObserver:forKeyPath:options:context:を使用して別のオブジェクトの変更をサブスクライブし、サブスクライブはremoveObserver:forKeyPath:を使用してサブスクライブしません。これらのメソッドは、呼び出されるだけで、書き込まれる必要はありません。通知はオブジェクトのobserveValueForKeyPath:ofObject:change:context:メソッドで処理されるため、このメソッドを記述する必要があります。最後に、オブジェクトはwillChangeValueForKey:didChangeValueForKey:を呼び出すことによって独自の通知を送信できます。コレクションの一部のみが変更されたという通知を送信する他の方法もありますが、ここでは使用しません。

私たちのFunctionTableは、変更サブスクリプションとサブスクリプションを処理することができますが、それでは、トランスフォーマーのどのプロパティを観察するのか知っていなければなりません。あなたはオブザーバーをサブスクライブして解除する各具体的な機能の変圧器にメソッドを追加することができます。

@implementation LinearTransformer 
... 
-(void)addObserver:(NSObject *)observer 
        options:(NSKeyValueObservingOptions)options 
        context:(void *)context 
{ 
    [self addObserver:observer 
      forKeyPath:@"slope" 
       options:options 
       context:context]; 
    [self addObserver:observer 
      forKeyPath:@"intercept" 
       options:options 
       context:context]; 
} 
-(void)removeObserver:(id)observer { 
    [self removeObserver:observer forKeyPath:@"slope"]; 
    [self removeObserver:observer forKeyPath:@"intercept"]; 
} 
@end 

しかし、これは、それぞれの方法で、それぞれの具体的な機能の変圧器間のコードの繰り返しの公平なビットが必要になります。いくつかの魔法の使い方(reflectionclosuresを、またはそれらはObjective-Cで呼ばれているように、blocks[2]))(彼らは&退会をサブスクライブするためKVOのメソッドと機能的に類似しているとして、addObserver:options:context:removeObserver:という名前)、私たちは、メソッドを追加することができますFunctionTransformerに、またはNSObjectにさえなります。オブジェクト上のすべてのプロパティを観察することはFunctionTransformerに限定されていないので、メソッドをNSObjectに追加します。これを行うには、OS X 10.6または​​とOS X 10.5が必要です。

上から順に、FunctionTableに変更してみましょう。関数トランスフォーマーを設定するときには、新しいサブタスクが追加されました。古いトランスフォーマーの変更を取り消し、新しいトランスフォーマーの変更をサブスクライブします。したがって、setF:メソッドは、NSObjectの新しいメソッドを使用するように更新する必要があります。このメソッドは、「NSObject_Properties.h」という名前のヘッダーで定義されます。これらのメソッドの実装についてはまだ心配する必要はありません。私たちはここでそれらを使うことができ、後で適切な実装を書くという信念を持っています。 FunctionTableは、変更通知(前述のobserveValueForKeyPath:ofObject:change:context:)を処理する新しい方法も必要です。

#import "NSObject_Properties.h" 
@interface FunctionTable 
... 
-(void)setF:(FunctionTransformer *)func { 
    if (func != f) { 
     [f removeObserver:self]; 
     [f release]; 
     f = [func retain]; 
     [f addObserver:self 
       options:NSKeyValueObservingOptionPrior 
       context:NULL]; 
     [NSValueTransformer setValueTransformer:f forName:kFunctionTransformer]; 
    } 
} 


- (void)observeValueForKeyPath:(NSString *)keyPath 
         ofObject:(id)object 
         change:(NSDictionary *)change 
         context:(void *)context 
{ 
    if (object == f) { 
     if ([[change objectForKey:NSKeyValueChangeNotificationIsPriorKey] boolValue]) { 
      [self willChangeValueForKey:@"xs"]; 
     } else { 
      [self didChangeValueForKey:@"xs"]; 
     } 
    } 
} 

次に、NSObjectに新しいメソッドを書きます。変更をサブスクライブまたはサブスクライブ解除するメソッドは、オブジェクトのプロパティをループするので、ループを実行するヘルパーメソッドforEachPropertyが必要になります。このヘルパーメソッドは、各プロパティで呼び出したブロックを受け取ります。サブスクリプションとアンサブスクリプションのメソッドは単にforEachPropertyを呼び出し、サブスクリプションを追加または削除するために各プロパティに標準KVOメソッド(addObserver:forKeyPath:options:context:removeObserver:forKeyPath:)を呼び出すブロックを渡します。

+0

iveはこれにちょうど試みました。それは動作しません。ちょうど多くの間違い。 – ash

+0

Iveはできるだけ早くこの作業を行いました。コンパイラのエラーがたくさんあることを除いて、非常に役に立ちます。また、必要なものではありません。手動で値を入力したり削除したり、変換を元に戻す必要はありません。テーブルを自動的に180のxの値に1ずつ増やし、それに対応するyの数を与えるだけです。私の実際のプログラムでは、傍受が必要ない。しかし、助けてくれてありがとう。私は本を​​手に入れるか、私に教えるためにキャンパスの講師を探す必要があります。残念ながら、私のすべての本は時代遅れであり、私が見つけることができるチュートリアルはすべてxcode 2のものです – ash

+0

エラーに関しては、基本版では10.5、先進版では10.6をターゲットにする必要があります。古いSDKをターゲットにすると、エラーが発生します。また、適切なファイルが含まれていることを確認する必要があります。 Objective-Cクラス用の新しいファイルをXCodeから作成するときは、標準のimport文(私がスキップしたもの)を追加する必要があります。余分な機能に関しては、ほとんどが無料で提供されました。それを含まないようにもっと努力していただろう。 y切片はもう少し仕事ではありましたが、それほど多かったわけではありません(4行4文字、NIBにはいくつかのウィジェットがあります)。これは何のためですか? – outis

関連する問題