【问题标题】:Is it ok not to invoke [super init] in a custom init method?可以不在自定义 init 方法中调用 [super init] 吗?
【发布时间】:2013-02-01 13:59:19
【问题描述】:

我有一个MKPolyline subblas,我想实现NSCoding,即

@interface RSRoutePolyline : MKPolyline <NSCoding>

I asked a question on the best way to encode the c-array and got an excellent answer。但是,MKPolyline 上没有定义 init 方法,即除了其类方法 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;
}

【问题讨论】:

  • 您的memcpy 方向错误。目的地先行。您可以只使用[pointData bytes] 而不是分配和复制数据。
  • @ughoavgfhw 谢谢,我已经编辑了我的答案.. 这条线是:MKMapPoint* points = (MKMapPoint*)[pointData bytes]; 你说什么?
  • __bridge_retained 需要吗?我对使用 c 桥接器感到困惑。
  • 不,我相信普通的__bridge 就足够了。我在stackoverflow.com/questions/14854521/where-and-how-to-bridge/… 中解决了这个问题
  • 我有 3 个很好的答案... 组合、类别和压倒一切的属性。 -我现在不知道该怎么办:)

标签: ios objective-c cocoa-touch nscoding


【解决方案1】:

你应该在 NSObject 的任何子类上调用一个 init 方法。由于 MKPolyline 是一个 NSObject,你应该初始化它。

但是 MKPolyline 没有方法,也没有 init。这是Objective C的意思是告诉你你不能继承它。

相反,正如 WDUK 建议的那样,定义您自己的类。它跟踪您的列表点,并管理 NSCoding 以根据需要保存和恢复它们。

 @interface RSPolyline: NSObject<NSCoding>

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

 - (MKPolyline*) polyLine;

 @end

您的类可以根据请求生成折线,如果性能有问题,可能会缓存结果。

作为一项规则,不要先进行继承。当你想扩展和改进一门课时,首先要考虑作文。

【讨论】:

  • BOOM - 我选择了这个答案。我认为它是最优雅的。谢谢!
【解决方案2】:

不打电话给[super init] 很脏,这对我的良好编程理念来说并不是什么好兆头。如果不自己调用 super ,它就不是真正的子类;只是依赖于调用便利构造函数的副作用的组合的混蛋。这么说,我相信您所描述的方法可以正常工作,但它违背了良好的 Objective-C 编程及其约定。

我的建议是使用MKPolyLine 作为MKPolyLine 实例,并使用一个类别来添加您需要的额外花里胡哨。至于添加额外的实例变量等,您可以使用关联对象。这个概念的介绍可以是found here,这个SO问题解决了它们与类别的使用:How do I use objc_setAssociatedObject/objc_getAssociatedObject inside an object?

【讨论】:

  • 好点,但是使用子类对我很有用,因为我的 mapView 上有不止一种类型的 MKPolyLine,所以我可以在 viewForOverlay: 中使用 [overlay isKindOfClass... 来区分它们。跨度>
  • 在这种情况下,您是否可以使用容器对象,或者遵循特定的协议来实现您所需要的,而不是继承MKPolyLine?我不确定在哪里使用它。仅仅因为继承很方便,并不意味着它是正确的做法。
【解决方案3】:

虽然通常允许在 init 方法中创建和返回不同的对象,但该行存在三个问题(如下所述)。相反,我建议重写pointspointCount 属性,以便您可以返回存储在实例变量中的值,并在实例变量为空时调用超级实现。然后,您的初始化程序只需设置这些实例变量,以便使用它们。

- (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];

但是,还有第三个问题不能这么容易解决。 polylineWithPoints:count: 不返回 RSRoutePolyline 对象,并且它返回的对象可能与您的子类的方法不兼容(例如,它可能不支持 NSCoding)。真的没有办法解决这个问题,所以你不能使用polylineWithPoints:count:

【讨论】:

  • 不管怎样,[RSPolyline polylineWithPoints:...] 实际上返回了一个子类的实例。不确定我是否会依赖它,因为方法签名并没有通过返回类型 id... 来表明这一点
猜你喜欢
  • 1970-01-01
  • 2011-03-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-04
  • 2016-07-15
  • 1970-01-01
  • 2023-04-06
相关资源
最近更新 更多