2
\$\begingroup\$

I've read some resources on implementing NSCopying and copyWithZone, but things are still not very clear. I see many implementations with allocWithZone, which seems to be deprecated, and with autorelease, which seems to be unnecessary with ARC.

I was wondering if I can get away with something more simple. Something like this:

MTSound.h

#import <Foundation/Foundation.h> @interface MTSound : NSObject <NSCopying> @property (nonatomic) float frequency; @property (nonatomic) float amplitude; @property (nonatomic) float duration; // Designated Initializer - (instancetype)initWithFrequency:(float)freq amplitude:(float)amp duration:(float)dur; + (instancetype)soundWithFrequency:(float)freq amplitude:(float)amp duration:(float)dur; @end 

MTSound.m

#import "MTSound.h" @implementation MTSound // Initializers - (instancetype)initWithFrequency:(float)freq amplitude:(float)amp duration:(float)dur { if (self = [super init]) { _frequency = freq; _amplitude = amp; _duration = dur; } return self; } // Class factory methods + (instancetype) soundWithFrequency:(float)freq amplitude:(float)amp duration:(float)dur { return [[self alloc] initWithFrequency:freq amplitude:amp duration:dur]; } // NSCopying protocol - (id)copyWithZone:(NSZone *)zone { return [[self class] soundWithFrequency:self.frequency amplitude:self.amplitude duration:self.duration]; } @end 

Is there something wrong with this approach? If so, what's the correct implementation?

\$\endgroup\$
0

1 Answer 1

2
\$\begingroup\$

Your implementation looks good to me. From the NSCopying reference:

Your options for implementing this protocol are as follows:

Implement NSCopying using alloc and init... in classes that don’t inherit copyWithZone:.

Implement NSCopying by invoking the superclass’s copyWithZone: when NSCopying behavior is inherited. If the superclass implementation might use the NSCopyObject function, make explicit assignments to pointer instance variables for retained objects.

Implement NSCopying by retaining the original instead of creating a new copy when the class and its contents are immutable.

If a subclass inherits NSCopying from its superclass and declares additional instance variables, the subclass has to override copyWithZone: to properly handle its own instance variables, invoking the superclass’s implementation first.

So you just need to know that if you are going to have classes that inherit from your MTSound, they will need to call [super copyWithZone] first, and then initialize their own instance variables after that.

You may also want to consider the first option of simply using alloc and init. If it is okay with Apple, then it should be alright for you to do it too, if you want.

Looking at the reference examples, it also seems perfectly fine to ignore the NSZone argument that is passed into copyWithZone. It seems to be common practice to ignore that argument. This Stack Overflow answer talks more about NSZone if you are interested.

I have just a couple more comments about the code. It seems to me that these comments:

// Initializers // Class factory methods // NSCopying protocol 

Would be more useful as pragmas, or could be removed completely. If you do this instead:

#pragma mark - Initializer 

Then you will get a bold heading in the method browser in Xcode, which can be useful for finding specific methods in a class. This is definitely a matter of preference, but simple comments like you have are not that useful and are a bit redundant.

Is there a reason that your properties such as @property (nonatomic) float frequency; are not readonly? From reading the code, I cannot tell if they will be modified later, or if the values will always stay the same. If they will always stay the same, I think readonly would be appropriate.

Overall the code is very clean and easy to understand.

\$\endgroup\$
2
  • \$\begingroup\$ Many thanks for the review, I really appreciate it. The idea is that the sound properties can change, so it's ok to have setters. I'm not using #pragma mark because my XCode version doesn't seem to support it. When I use it nothing appears in the method browser. I'm stuck with Lion and XCode 4 for now. \$\endgroup\$ Commented Oct 27, 2014 at 15:02
  • \$\begingroup\$ No problem! Thanks for the clarification. \$\endgroup\$ Commented Oct 27, 2014 at 15:39

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.