为代理人提供“强”参考是否有好处? [英] Is it ever Ok to have a 'strong' reference for a delegate?

查看:124
本文介绍了为代理人提供“强”参考是否有好处?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个类从URL中检索JSON,并通过协议/委托模式返回数据。



MRDelegateClass.h / p>

  #import< Foundation / Foundation.h> 

@protocol MRDelegateClassProtocol
@optional
- (void)dataRetrieved:(NSDictionary *)json;
- (void)dataFailed:(NSError *)错误;
@end

@interface MRDelegateClass:NSObject
@property(strong)id< MRDelegateClassProtocol>代表;

- (void)getJSONData;
@end

请注意,我使用 strong 为我的委托属性。更多关于这一点...



我正在尝试编写一个以包含基于块的格式实现getJSONData的包装类。



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

  #importMRBlockWrapperClassForDelegate.h
#importMRDelegateClass.h

@interface DelegateBlock:NSObject < MRDelegateClassProtocol>
@property(nonatomic,copy)SuccessBlock successBlock;
@property(nonatomic,copy)ErrorBlock errorBlock;
@end

@implementation DelegateBlock
- (id)initWithSuccessBlock:(SuccessBlock)aSuccessBlock和ErrorBlock:(ErrorBlock)aErrorBlock {
self = [super init];
if(self){
_successBlock = aSuccessBlock;
_errorBlock = aErrorBlock;
}
return self;
}

#pragma mark - < MRDelegateClass>协议
- (void)dataRetrieved:(NSDictionary *)json {
self.successBlock(json);
}
- (void)dataFailed:(NSError *)错误{
self.errorBlock(error);
}
@end

//主类
@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; //将代理设置为新的委托块
[delegateClassInstance getJSONData];
}

@end

我来到客观世界相对较近(只住在ARC时代,并且仍然与块相关),诚然,我对内存管理的理解在于事物的细微变化。



这段代码似乎工作正常,但只有当我的代理为 strong 时。我明白我的代表应该是 weak ,以避免潜在的保留周期。看着乐器,我发现分配不会随着电话持续增长。但是,我认为最佳做法是让 weak 代表。



问题



Q1)有没有'code>强力代表



Q2)如何实现基于块的包装器,使底层类的代理为 weak delegate(即防止* delegateBlock在之前被释放它接收协议方法)?

解决方案

Q1 - 是的。当您指出自己的代理属性是弱的是一个建议,以帮助避免保留周期。所以没有任何错误具有强大的委托,但如果你的班级的客户希望它是弱的,你可能会让他们惊喜。更好的方法是保持代理薄弱,并为服务器端(与委托属性的类)在内部保持强有力的参考需求。由于@Scott指出了在 NSURLConnection 中执行此操作的Apple文档。当然,这种方法并不能解决您的问题 - 您希望服务器为您保留代表...



Q2 - 从客户端查看问题只要具有弱引用的服务器需要它,就是如何保持代理活动。有一个称为关联对象的问题的标准解决方案。简而言之,Objective-C运行库基本上允许对象的密钥集合与另一个对象相关联,以及关联策略,该关联策略指示关联应该持续多长时间。要使用这个机制,你只需要选择你自己的唯一键,它的类型是 void * ,即一个地址。以下代码大纲显示了如何使用 NSOpenPanel 作为示例:

  #import< objc / runtime.h> //导入关联对象函数

static char myUniqueKey; //该变量的地址将是唯一的

NSOpenPanel * panel = [NSOpenPanel openPanel];

MyOpenPanelDelegate * myDelegate = [MyOpenPanelDelegate new];
//将代理与面板相关联,使其与面板本身一样长。
objc_setAssociatedObject(panel,& myUniqueKey,myDelegate,OBJC_ASSOCIATION_RETAIN);
//作为面板委派分配
[panel setDelegate:myDelegate];

协会政策 OBJC_ASSOCIATION_RETAIN 将保留已通过在对象( myDelegate )中只要与它相关联的对象(面板),然后释放它。 / p>

采用此解决方案避免使委托属性本身变强,并允许客户端控制委托是否保留。如果您还在实施服务器,您可以提供一种方法来执行此操作,也许 associatedDelegate:?,以避免客户端需要定义密钥并调用 objc_setAssociatedObject 本身。 (或者您可以使用类别将其添加到现有课程中。)



HTH。


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

Note that I'm using strong for my delegate property. More about that later...

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

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.

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.

Questions

Q1) is it ever 'ok' to have strong delegates

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 - 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 - 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];

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.

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.

这篇关于为代理人提供“强”参考是否有好处?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆