Objective-C:使用弱引用
Objective-C: work with weak references
我有几个 class:
Book
、Publisher
、Author
和 Genre
.
所以这里是主要的 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
和他的实现 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
我有委托 class - 流派,所以为了避免强引用循环,Book
的 Genre
属性 必须 weak.
此时在 Book.m 初始值设定项中:
_genre = [[Genre alloc] initWithGenreName:genreName];
它将为零,因为 Genre
实例将在分配后立即释放。
根据 Dan 的评论,这是我的 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
我的问题是"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?"。
解决方案:在我的例子中,它是流派的集合,我将我的弱 属性 引用引用到我的集合中的一个对象。
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]];
一个解决方案是使类型 属性 成为强有力的参考。
如果您真的需要将 Genre 设为弱引用,
您可以通过将所有流派存储在 table 中并使用如下方式静态访问它们来解决此问题:
_genre = [Genre forName:genreName]
然后静态 forName 方法会在所有类型的 table 中查找正确的类型。由于将流派存储在 table 中会保留该对象,因此不会在分配时立即释放它。
@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
要记住的规则是 - 强属性会增加引用计数,而弱属性则不会 - 当引用计数变为 0 时,将释放适当的属性。因此,就 Genre 而言——在您的代码中,没有对它的强引用,因此它被释放了。真正的解决方案是让另一个 class 拥有流派 'owned'。这个 class 将管理流派,创建它们并保持对它们的强烈引用,例如,可能在流派数组中。您的 'strong' 流派将与初始化程序一起传递,然后弱引用是正确的方法,防止保留循环,但 dealloc 被流派 属性 的强 属性 阻止] 已经有了 - 这有意义吗?
在某种程度上,将您的对象视为需要 'owner' class 是有道理的,其中定义了使它们保持活动状态的强引用。然后当传递给其他 class 像你的书 class 时,那些引用很弱,这会阻止你所说的保留周期。这本书 class 不是所有者,但其他人是 - 所以它不会消失。
弱引用不会创建引用计数。如果只有对对象的弱引用,则该对象将被释放。这意味着如果你想让一个对象保持活动状态,你要么使用强引用,要么使用强引用将它存储在其他地方。
您使用弱引用来避免引用循环,以及用于目前保存在其他地方但可能在某个时候消失的对象。在您的情况下,使用弱引用是您无法正常工作的。
我有几个 class:
Book
、Publisher
、Author
和 Genre
.
所以这里是主要的 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
和他的实现 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
我有委托 class - 流派,所以为了避免强引用循环,Book
的 Genre
属性 必须 weak.
此时在 Book.m 初始值设定项中:
_genre = [[Genre alloc] initWithGenreName:genreName];
它将为零,因为 Genre
实例将在分配后立即释放。
根据 Dan 的评论,这是我的 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
我的问题是"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?"。
解决方案:在我的例子中,它是流派的集合,我将我的弱 属性 引用引用到我的集合中的一个对象。
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]];
一个解决方案是使类型 属性 成为强有力的参考。
如果您真的需要将 Genre 设为弱引用, 您可以通过将所有流派存储在 table 中并使用如下方式静态访问它们来解决此问题:
_genre = [Genre forName:genreName]
然后静态 forName 方法会在所有类型的 table 中查找正确的类型。由于将流派存储在 table 中会保留该对象,因此不会在分配时立即释放它。
@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
要记住的规则是 - 强属性会增加引用计数,而弱属性则不会 - 当引用计数变为 0 时,将释放适当的属性。因此,就 Genre 而言——在您的代码中,没有对它的强引用,因此它被释放了。真正的解决方案是让另一个 class 拥有流派 'owned'。这个 class 将管理流派,创建它们并保持对它们的强烈引用,例如,可能在流派数组中。您的 'strong' 流派将与初始化程序一起传递,然后弱引用是正确的方法,防止保留循环,但 dealloc 被流派 属性 的强 属性 阻止] 已经有了 - 这有意义吗?
在某种程度上,将您的对象视为需要 'owner' class 是有道理的,其中定义了使它们保持活动状态的强引用。然后当传递给其他 class 像你的书 class 时,那些引用很弱,这会阻止你所说的保留周期。这本书 class 不是所有者,但其他人是 - 所以它不会消失。
弱引用不会创建引用计数。如果只有对对象的弱引用,则该对象将被释放。这意味着如果你想让一个对象保持活动状态,你要么使用强引用,要么使用强引用将它存储在其他地方。
您使用弱引用来避免引用循环,以及用于目前保存在其他地方但可能在某个时候消失的对象。在您的情况下,使用弱引用是您无法正常工作的。