1
votes

I have started a Master Detail application and left the generated code untouched. I created and added two additional classes: a book class(contains an NSString for a title, author, and summary) and also a data controller class(contains a mutable array to store the books).

My understanding of @property attributes after reading Apple doc and others is this:

  1. strong - default, creates ownership of an object
  2. weak - alternative to strong, used to avoid retain cycles
  3. copy - creates a copy of the existing object and takes ownership of that
  4. nonatomic - disregards any sort of thread safety

This code throws a segmentation fault in addBookToList when the @property AJKBook is declared with the copy attribute and I don't understand why.

@interface AJKBookDataController ()

// when current book uses the copy attribute code seg faults in addBookToList
@property (nonatomic) AJKBook  *currentBook;
@property (nonatomic, copy) NSString *currentValue;

- (void)populateBookList;
- (void)addBookToBookList;

@end

@implementation AJKBookDataController

- (id)init
{
    self = [super init];
    if (self) {
        _bookList = [[NSMutableArray alloc] init];
        _currentBook = [[AJKBook alloc] init];
        _currentValue = [[NSString alloc] init];
        [self populateBookList];
        return self;
    }
    return nil;
}

- (void)setBookList:(NSMutableArray *)bookList
{
    // this bit of code ensures bookList stays mutable
    if (_bookList != bookList) {
        _bookList = [bookList mutableCopy];
    }
}

- (void)populateBookList
{
    NSURL *url = [NSURL URLWithString:@"https://sites.google.com/site/iphonesdktutorials/xml/Books.xml"];

    NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:url];

    [parser setDelegate:self];
    [parser parse];

    NSLog(@"%@", [self.bookList description]);
}

- (void)addBookToBookList
{
    [self.bookList addObject:self.currentBook];
    self.currentBook = [[AJKBook alloc] init];
}
...
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
    if ([elementName isEqualToString:@"title"]) {
        // [self.currentBook title:self.currentValue];
        self.currentBook.title = self.currentValue;
    } else if ([elementName isEqualToString:@"author"]) {
        self.currentBook.author = self.currentValue;
    } else if ([elementName isEqualToString:@"summary"]) {
        self.currentBook.summary = self.currentValue;
    } else if ([elementName isEqualToString:@"Book"]) {
        [self addBookToBookList];
    }

    self.currentValue = [NSString stringWithFormat:@""];
}
@end
1
But you haven't used the copy property, because you accessed the synthesized property, so the string doesn't get copied. Are you sure that the code crashes at the third like inside the if? It seems ok to me.Ramy Al Zuhouri
@RamyAlZuhouri I'm sorry I should have reverted back to code that included the copy property on currentBook. Digging through the output gives this: -[AJKBook copyWithZone:]: unrecognized selector sent to instance 0x8982390 I was unaware I needed to implement my own copy method.Alex John

1 Answers

3
votes

if you want to use copy for your custom classes you have to implement – copyWithZone: in those classes.

But you don't have to use copy. Often strong is good enough. copy is mostly used for NSString properties because you want to prevent that a NSMutableString is assigned and later changed from outside the class.

You have to think if you really need to copy the current book. If something is named current in my opinion that's a strong indication that you do NOT want to copy. If the only assignment is from [[AJKBook alloc] init]; copy does not make sense at all.