1

MKPolyline実装したいサブブラスがありNSCodingます。

@interface RSRoutePolyline : MKPolyline <NSCoding>

c-arrayをエンコードする最良の方法について質問したところ、優れた回答が得られました。ただし、に定義されたinitメソッドはありませんMKPolyline。つまり、クラスメソッド以外にデータを与える方法はありませんpolylineWithPoints:points

このコードは私のコメントで大丈夫ですか?

- (void)encodeWithCoder:(NSCoder *)aCoder
{
    MKMapPoint *points = self.points;
    NSUInteger pointCount = self.pointCount;

    NSData *pointData = [NSData dataWithBytes:points length:pointCount * sizeof(MKMapPoint)];
    [aCoder encodeObject:pointData forKey:@"points"];
    [aCoder encodeInteger:pointCount forKey:@"pointCount"];
}

- (id)initWithCoder:(NSCoder *)aDecoder
{
    NSData* pointData = [aDecoder decodeObjectForKey:@"points"];
    NSUInteger pointCount = [aDecoder decodeIntegerForKey:@"pointCount"];

    // Edit here from @ughoavgfhw's comment
    MKMapPoint* points = (MKMapPoint*)[pointData bytes];

    // Is this line ok?
    self = (RSRoutePolyline*)[MKPolyline polylineWithPoints:points count:pointCount];

    return self;
}
4

3 に答える 3

2

を呼び出さないのは汚いこと[super init]であり、良いプログラミングの私の考えとはうまくいきません。自分で super を呼び出さないと、それは真のサブクラスではありません。便利なコンストラクターを呼び出すことの副作用に依存する構成の野郎化です。そうは言っても、説明されている方法は問題なく機能すると思いますが、優れたObjective-Cプログラミングとその慣習の粒度に反します。

私が提案するのはMKPolyLineMKPolyLineインスタンスとして使用し、カテゴリを使用して必要な機能を追加することです. インスタンス変数などを追加する場合は、関連付けられたオブジェクトを使用できます。この概念の紹介はここにあります。この SO の質問では、カテゴリでの使用について説明しています:オブジェクト内で objc_setAssociatedObject/objc_getAssociatedObject を使用するにはどうすればよいですか?

于 2013-02-16T19:46:50.993 に答える
2

NSObject の任意のサブクラスで init メソッドを呼び出す必要があります。MKPolyline は NSObject であるため、初期化する必要があります。

しかし、MKPolyline にはメソッドも初期化もありません。これは、Objective C がサブクラス化できないことを示していました。

代わりに、WDUK が提案したように、独自のクラスを定義します。リスト ポイント ポイントを追跡し、NSCoding を管理して必要に応じて保存および復元します。

 @interface RSPolyline: NSObject<NSCoding>

 - (id) initWithPoints: (NSArray*) points;
 - (id) initWithCoder:(NSCoder *)aDecoder;
 - (void) encodeWithCoder:(NSCoder *)aCoder;

 - (MKPolyline*) polyLine;

 @end

クラスは要求に応じてポリラインを生成できます。パフォーマンスが問題になる場合は、おそらく結果をキャッシュします。

原則として、最初に継承に手を出さないでください。クラスを拡張および改善したい場合は、まず構成を考えてください。

于 2013-02-16T20:01:56.997 に答える
1

通常、init メソッドで別のオブジェクトを作成して返すことは許可されていますが、その行には 3 つの問題があります (以下で説明します)。pointsこれの代わりに、プロパティとプロパティをオーバーライドしてpointCount、インスタンス変数に格納された値を返すことができるようにし、インスタンス変数が空の場合はスーパー実装を呼び出すことをお勧めします。次に、イニシャライザはこれらのインスタンス変数を使用するように設定するだけです。

- (MKMapPoint *)points {
    if(myPointsIvar == NULL) return [super points];
    else return myPointsIvar;
}
// similarly for pointCount

最初の問題は、新しいオブジェクトを作成しているが、古いオブジェクトを解放していないことです。つまり、リークしているということです。結果を別の変数に格納してから、self を解放してから結果を返す必要があります (self に格納する必要はありません)。

次に、polylineWithPoints:count:自動解放されたオブジェクトを返しますがinitWithCoder:、保持されているオブジェクトを返す必要があります。別の保持がない限り、まだ使用している間に割り当てが解除される可能性があります。

これらが唯一の問題である場合、次のように両方を解決できます。

MKPolyline *result = [MKPolyline polylineWithPoints:points count:pointCount];
[self release];
return [result retain];

しかし、そう簡単には解決できない第3の問題があります。polylineWithPoints:count:RSRoutePolylineオブジェクトを返さず、それが返すオブジェクトはサブクラスのメソッドと互換性がない可能性があります (たとえば、NSCoding をサポートしていない可能性があります)。これを修正する方法は本当にないので、使用できませんpolylineWithPoints:count:

于 2013-02-16T19:54:30.653 に答える