Reputation: 13
I have a few classes:
Book
, Publisher
, Author
and Genre
.
So here is the main class Book.h:
#import "Publisher.h"
#import "Author.h"
#import "Genre.h"
@interface Book : NSObject
@property (nonatomic, strong) NSString *bookName;
@property (nonatomic, strong) Author *author;
@property (nonatomic, strong) Publisher *publisher;
@property (nonatomic, weak) Genre *genre;
- (instancetype)initWithBookName:(NSString *)name andAuthorName:(NSString *)authorName
andPublisher:(NSString *)publisherName andGenreName:(__strong NSString *)genreName;
- (NSString *)description;
@end
and his implementation Book.m:
#import "Genre.h"
#import "Book.h"
#import <Foundation/Foundation.h>
@implementation Book
- (instancetype)initWithBookName:(NSString *)name andAuthorName:(NSString *)authorName
andPublisher:(NSString *)publisherName andGenreName:(__strong NSString *)genreName{
self = [super init];
if (self) {
_bookName = [name copy];
_author = [[Author alloc] initWithAuthorName:authorName];
_publisher = [[Publisher alloc] initWithPublisherName:publisherName];
_genre = [[Genre alloc] initWithGenreName:genreName];
}
return self;
}
- (instancetype)init {
return [self initWithBookName:@"unnamed" andAuthorName:@"unnamed" andPublisher:@"unnamed" andGenreName:@"unnamed"];
}
- (NSString *)description {
return [NSString stringWithFormat: @"Book: %@, Author: %@, Genre: %@", self.bookName, self.author, self.genre];
}
@end
I have delegate class - Genre, so to avoid strong reference cycles, a Book
's Genre
property must be weak.
At this point in the Book.m initializer:
_genre = [[Genre alloc] initWithGenreName:genreName];
it will be nil, because the Genre
instance will be deallocated right after assignment.
According to Dan comment, here is my Genre.h:
#import <Foundation/Foundation.h>
@class Book;
@interface Genre : NSObject
@property (nonatomic, strong) NSString *genreName;
@property (nonatomic, strong) NSArray <Book *> *books;
- (instancetype)initWithGenreName:(NSString *)name andBooks:(NSArray <Book *>*)books;
- (instancetype)initWithGenreName:(NSString *)name;
- (NSString *)description;
@end
My question is "What is the best way to store genre object (genreName -> Genre constructor -> genre object) at weak property genre and how do I can store it without using constructor for assignment to weak property?".
SOLUTION: In my case it was collection of Genre and I take my weak property reference to one of objects from my collection.
Genre * genre1 = [[Genre alloc]initWithGenreName:@"Comedy"];
Genre * genre2 = [[Genre alloc]initWithGenreName:@"Drama"];
Genre * genre3 = [[Genre alloc]initWithGenreName:@"Fantastic"];
Genre * genre4 = [[Genre alloc]initWithGenreName:@"National"];
NSArray <Genre*> *genres = @[genre1, genre2, genre3, genre4];
Book *book1 = [[Book alloc] initWithBookName:@"Book #3!" andAuthorName:@"Grinch Burs" andPublisher:@"Ableton" andGenre:[genres objectAtIndex:0]];
Upvotes: 1
Views: 1356
Reputation: 52530
A weak reference does not create a reference count. If there are only weak references to an object, the object will be deallocated. That means if you want an object to stay alive, you either use a strong reference, or you store it somewhere else using a strong reference.
You use weak references to avoid reference cycles, and for objects that are held elsewhere at the moment but might disappear at some point. In your case, using a weak reference is something you won't get working properly.
Upvotes: 0
Reputation: 1320
The rule to remember is - strong properties increase the reference count, while weak ones do not - and when the reference count gets to 0, a proper is deallocated. So in the case of Genre - at your point in the code, there are no strong references to it so it is deallocated. The solution really is to have the Genres 'owned' by another class. This class would manage the genres, creating them and keeping strong references to them, perhaps in for eg an array of Genres. Your 'strong' genre would be passed in with the initializer, and then the weak reference is the correct approach, preventing a retain cycle, but the dealloc is prevented by the strong property that the Genre property already has - does that make sense?
In a way it makes sense to think of your objects as needing an 'owner' class, where strong references are defined that keep them alive. Then when passed to other classes like your Book class, those have weak references, which prevents the retain cycle as you say. The book class isnt the owner, but someone else is - so it doesnt go away.
Upvotes: 1
Reputation: 12109
One solution would be to make the genre property a strong reference.
If you really need to make Genre a weak reference, you can solve this by storing all genres in a table and access them statically with something like this:
_genre = [Genre forName:genreName]
The static forName method would then look the correct genre up in a table of all genres. As storing the genre in a table would retain the object, it will not be released immediately on assignment.
@implementation Genre
static NSDictionary* genres;
+ (void) initGenres {
// initialize the dictionary and insert all genres
// or just initalize the dictionary and insert genres on demand
}
+ (Genre*) forName: (NSString*) genreName {
if (!genres) {
[Genre initGenres];
}
//lookup the genre in the dictionary and return it
}
@end
Upvotes: 0