我有一个从 URL 检索 JSON 并通过协议/委托模式返回数据的类.
I have a class that retrieves JSON from a URL and returns the data via the protocol/delegate pattern.
MRDelegateClass.h
#import <Foundation/Foundation.h>
@protocol MRDelegateClassProtocol
@optional
- (void)dataRetrieved:(NSDictionary *)json;
- (void)dataFailed:(NSError *)error;
@end
@interface MRDelegateClass : NSObject
@property (strong) id <MRDelegateClassProtocol> delegate;
- (void)getJSONData;
@end
请注意,我将 strong
用于我的委托属性.稍后再详细介绍...
Note that I'm using strong
for my delegate property. More about that later...
我正在尝试编写一个以基于块的格式实现 getJSONData 的包装器"类.
I am trying to write a 'wrapper' class that implements getJSONData in a block-based format.
MRBlockWrapperClassForDelegate.h
#import <Foundation/Foundation.h>
typedef void(^SuccessBlock)(NSDictionary *json);
typedef void(^ErrorBlock)(NSError *error);
@interface MRBlockWrapperClassForDelegate : NSObject
+ (void)getJSONWithSuccess:(SuccessBlock)success orError:(ErrorBlock)error;
@end
MRBlockWrapperClassForDelegate.m
#import "MRBlockWrapperClassForDelegate.h"
#import "MRDelegateClass.h"
@interface DelegateBlock:NSObject <MRDelegateClassProtocol>
@property (nonatomic, copy) SuccessBlock successBlock;
@property (nonatomic, copy) ErrorBlock errorBlock;
@end
@implementation DelegateBlock
- (id)initWithSuccessBlock:(SuccessBlock)aSuccessBlock andErrorBlock:(ErrorBlock)aErrorBlock {
self = [super init];
if (self) {
_successBlock = aSuccessBlock;
_errorBlock = aErrorBlock;
}
return self;
}
#pragma mark - <MRDelegateClass> protocols
- (void)dataRetrieved:(NSDictionary *)json {
self.successBlock(json);
}
- (void)dataFailed:(NSError *)error {
self.errorBlock(error);
}
@end
// main class
@interface MRBlockWrapperClassForDelegate()
@end
@implementation MRBlockWrapperClassForDelegate
+ (void)getJSONWithSuccess:(SuccessBlock)success orError:(ErrorBlock)error {
MRDelegateClass *delegateClassInstance = [MRDelegateClass new];
DelegateBlock *delegateBlock = [[DelegateBlock alloc] initWithSuccessBlock:success andErrorBlock:error];
delegateClassInstance.delegate = delegateBlock; // set the delegate as the new delegate block
[delegateClassInstance getJSONData];
}
@end
我最近才接触到 Objective-c 世界(只生活在 ARC 时代,并且仍在接受块),诚然,我对内存管理的理解还比较肤浅.
I've come to the objective-c world relatively recently (only lived in ARC times, and still coming to terms with blocks) and admittedly my understanding of memory management is on the slimmer side of things.
此代码似乎可以正常工作,但前提是我的委托是 strong
.我知道我的委托应该是 weak
以避免潜在的保留周期.查看工具,我发现分配不会随着持续的调用而继续增长.但是,我认为最佳实践"是拥有 weak
代表.
This code seems to work fine, but only if I have my delegate as strong
. I understand that my delegate should be weak
to avoid potential retain-cycles. Looking in instruments, I find that allocations do not continue to grow with continued calls. However, I believe 'best practice' is to have weak
delegates.
问题
Q1) 拥有 strong
代表是否可以"
Q1) is it ever 'ok' to have strong
delegates
Q2) 我如何实现基于块的包装器,将底层类的委托保留为 weak
委托(即防止 *delegateBlock 在收到协议方法之前被释放)?
Q2) how could I implement the block-based wrapper leaving the delegate of the underlying class as weak
delegate (ie. prevent the *delegateBlock from being deallocated before it receives the protocol methods)?
Q1 - 是的.正如您指出的那样,委托属性较弱是一个建议,以帮助避免保留周期.所以本身拥有一个强大的委托并没有什么错,但是如果你班级的客户认为它很弱,你可能会让他们感到惊讶.更好的方法是保持委托弱,并为服务器端(具有委托属性的类)在内部为它需要的那些时期保持强引用.正如@Scott 指出的那样,Apple 文档为 NSURLConnection
执行此操作.当然,这种方法并不能解决您的问题 - 您希望服务器为您保留委托...
Q1 - Yes. As you point out yourself having delegate properties being weak is a recommendation to help avoid retain cycles. So there is nothing wrong per se with having a strong delegate, but if the clients of your class expect it to be weak you may cause them surprises. The better approach is to keep the delegate weak and for the server side (the class with the delegate property) to keep a strong reference internally for those periods it needs one. As @Scott points out Apple documents doing this for NSURLConnection
. Of course that approach doesn't solve your issue - where you want the server to retain the delegate for you...
Q2 - 从客户端来看,问题是如何让代理保持活动状态,只要对它的弱引用的服务器需要它.这个问题有一个标准的解决方案,称为关联对象.简而言之,Objective-C 运行时本质上允许对象的键集合与另一个对象相关联,以及一个关联策略,该策略说明该关联应该持续多长时间.要使用此机制,您只需选择自己的唯一键,它的类型为 void *
- 即 address.以下代码大纲显示了如何使用 NSOpenPanel
作为示例:
Q2 - Looked at from the client side the problem is how to keep a delegate alive as long as a server with a weak reference to it requires it. There is a standard solution to this problem called associated objects. In brief the Objective-C runtime essentially allows a key-collection of objects to be associated with another object, along with an association policy which states how long that association should last. To use this mechanism you just need to pick your own unique key, which is of type void *
- i.e. an address. The following code outline shows how to use this using NSOpenPanel
as an example:
#import <objc/runtime.h> // import associated object functions
static char myUniqueKey; // the address of this variable is going to be unique
NSOpenPanel *panel = [NSOpenPanel openPanel];
MyOpenPanelDelegate *myDelegate = [MyOpenPanelDelegate new];
// associate the delegate with the panel so it lives just as long as the panel itself
objc_setAssociatedObject(panel, &myUniqueKey, myDelegate, OBJC_ASSOCIATION_RETAIN);
// assign as the panel delegate
[panel setDelegate:myDelegate];
关联策略 OBJC_ASSOCIATION_RETAIN
将保留传入的对象 (myDelegate
),只要它与之关联的对象 (panel
)然后释放它.
The association policy OBJC_ASSOCIATION_RETAIN
will retain the passed in object (myDelegate
) for as long as the object it is associated with (panel
) and then release it.
采用这种解决方案可以避免让委托属性本身变得强大,并允许客户端控制是否保留委托.如果你也在实现服务器,你当然可以提供一个方法来做到这一点,也许是 associatedDelegate:
?,以避免客户端需要定义键并调用 objc_setAssociatedObject
本身.(或者您可以使用类别将其添加到现有类中.)
Adopting this solution avoids making the delegate property itself strong and allows the client to control whether the delegate is retained. If you are also implementing the server you can of course provide a method to do this, maybe associatedDelegate:
?, to avoid the client needing to define the key and call objc_setAssociatedObject
itself. (Or you can add it to an existing class using a category.)
HTH.
这篇关于是否可以为代表提供“强"参考?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!