Creating and using a dummy NSData subclass doesn&#

2019-02-25 09:41发布

问题:

I have a problem with creating my own subclass of NSData, which I want to have a custom description method. Even creating a dummy NSData subclass:

@interface MyData : NSData {}
@end

and

@implementation MyData
@end

and using it results in weird bugs (the function that uses it never exits, and control somehow returns to the run loop). I thought that maybe I am responsible for rewriting the designated initializers of NSData (calling the super implementation), but none is mentioned in the doc. So:

  • what are the designated initializers of NSData?
  • what is the bare minimum I need to write for a dummy subclass of NSData?

回答1:

Making an NSData subclass is difficult because (as drewag noted) it is a member of a class cluster. From the Binary Data Programming Guide:

...data objects are not actual instances of the NSData or NSMutableData classes but instead are instances of one of their private subclasses.

When you do [[NSData alloc] initWith...] you don't get back an NSData; you probably get back an NSConcreteData. The extraordinary Cocoa With Love has a discussion and demonstration of subclassing class clusters.

The best (and most idiomatic) option is probably composition: your custom class should simply contain an NSData ivar, and implement a description method that operates on that enclosed object.

While drewag's response is technically correct, this is a dangerous technique to use on Cocoa classes; it will override the description method of every NSData object in the program, whether you create it directly or not.

In the specific case of the description method this may be okay, but for another method more likely to be relied upon by other objects in the framework, it could cause large, hard-to-trace problems. You should only do this if you are sure that there is no other way.

It would be far better to create a category and method with a prefix:

@interface NSData (FX_Description) 
- (NSString *)FX_description;
@end

The Apple docs specifically mention this category-override technique and advise against it:

Because the methods declared in a category are added to an existing class, you need to be very careful about method names.

If the name of a method declared in a category is the same as a method in the original class, or a method in another category on the same class (or even a superclass), the behavior is undefined as to which method implementation is used at runtime.

An earlier version of the docs went on to say:

The very presence of some category methods may cause behavior changes across all frameworks. For example, if you override the windowWillClose: delegate method in a category on NSObject, all window delegates in your program then respond using the category method; the behavior of all your instances of NSWindow may change. Categories you add on a framework class may cause mysterious changes in behavior and lead to crashes. [Emphasis mine.]



回答2:

If all you want is to override a single function "description" consider using a "Category" instead:

@interface NSData (MyData)
-(NSString*)description;
@end

@implimentation NSData (MyData)
-(NSString*)description
{
    return @"something";
}
@end

Then, you can use this function on any instance of NSData.

It is very difficult to subclass NSData because it is a "Class Cluster." The public API treats it as one class, but in reality it is a collection of hidden subclasses. You can research overriding a class cluster, but it is almost never needed. Another option is to create your "MyData" class with NSData as a member variable instead of using a subclass.