Objective c 有一个';强';代表的参考资料?

Objective c 有一个';强';代表的参考资料?,objective-c,memory-management,delegates,automatic-ref-counting,objective-c-blocks,Objective C,Memory Management,Delegates,Automatic Ref Counting,Objective C Blocks,我有一个从URL检索JSON并通过协议/委托模式返回数据的类 MRDelegateClass.h mrblockwrappersclassfordelegate.m #导入“mrblockwrappersclassfordelegate.h” #导入“MRDelegateClass.h” @接口DelegateBlock:NSObject @属性(非原子,复制)SuccessBlock SuccessBlock; @属性(非原子,复制)ErrorBlock ErrorBlock; @结束 @实现

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

MRDelegateClass.h

mrblockwrappersclassfordelegate.m

#导入“mrblockwrappersclassfordelegate.h”
#导入“MRDelegateClass.h”
@接口DelegateBlock:NSObject
@属性(非原子,复制)SuccessBlock SuccessBlock;
@属性(非原子,复制)ErrorBlock ErrorBlock;
@结束
@实现委派块
-(id)initWithSuccessBlock:(SuccessBlock)AsAccess Block andErrorBlock:(ErrorBlock)AerorBlock{
self=[super init];
如果(自我){
_successBlock=asaccessblock;
_errorBlock=AerorBlock;
}
回归自我;
}
#pragma标记-协议
-(void)数据检索:(NSDictionary*)json{
self.successBlock(json);
}
-(void)数据失败:(n错误*)错误{
自身错误块(错误);
}
@结束
//主类
@接口MRBlockWrapperClassForDelegate()
@结束
@实现MRBlockWrapperClassForDelegate
+(void)getJSONWithSuccess:(SuccessBlock)success或error:(ErrorBlock)error{
MRDelegateClass*delegateClassInstance=[MRDelegateClass新建];
DelegateBlock*DelegateBlock=[[DelegateBlock alloc]initWithSuccessBlock:success androrblock:error];
delegateClassInstance.delegate=delegateBlock;//将该委托设置为新的委托块
[delegateClassInstance getJSONData];
}
@结束
我最近才来到objective-c世界(只生活在ARC时代,现在仍在接受块),无可否认,我对内存管理的理解是比较狭隘的

此代码似乎工作正常,但前提是我的委托为
strong
。我知道我的代表应该是
弱的
,以避免潜在的保留周期。在工具方面,我发现,随着不断的调用,分配不会继续增长。然而,我认为“最佳实践”是让
弱的
代理

问题

Q1)拥有
strong
代表是否“合适”


问题2)如何实现基于块的包装器,使基础类的委托保持为
委托(即防止*delegateBlock在收到协议方法之前被解除分配)?

您是正确的,因为委托通常是弱引用的。然而,在一些用例中,强引用是首选的,甚至是必要的。苹果将此应用于:

在下载过程中,连接保持对代理的强引用。当连接完成加载、失败或取消时,它将释放该强引用

NSURLConnection
实例只能使用一次。完成后(失败或成功),它将释放委托,并且由于委托是只读的,因此无法(安全地)重用


你可以做类似的事情。在
dataRetrieved
dataFailed
方法中,将代理设置为
nil
。如果要重用对象,可能不需要将委托设置为只读,但必须重新分配委托。

Q1-是。正如您所指出的,建议您将委托属性设置为弱属性,以帮助避免保留周期。因此,拥有一个强大的委托本身并没有错,但如果你的类的客户认为它很弱,你可能会给他们带来惊喜。更好的方法是保持委托的弱性,对于服务器端(具有delegate属性的类),在需要的时间段内保持强引用。正如@Scott指出的,苹果公司的文档是为
NSURLConnection
这样做的。当然,这种方法并不能解决您的问题——您希望服务器为您保留代理

问题2-从客户端看,问题在于如何在对委托的引用较弱的服务器需要委托时保持委托的活动状态。这个问题有一个标准的解决方案称为关联对象。简言之,Objective-C运行时本质上允许对象的键集合与另一个对象相关联,并提供一个关联策略,该策略说明该关联应该持续多长时间。要使用此机制,您只需选择自己的唯一密钥,该密钥类型为
void*
——即地址。以下代码大纲显示了如何使用
NSOpenPanel
作为示例:

#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];
#导入//导入关联的对象函数
静态字符myUniqueKey;//此变量的地址将是唯一的
NSOpenPanel*面板=[NSOpenPanel openPanel];
MyOpenPanelDelegate*myDelegate=[MyOpenPanelDelegate新建];
//将代理与面板关联,使其与面板本身一样长
objc_setAssociatedObject(面板和myUniqueKey、myDelegate、objc_关联_RETAIN);
//指定为面板代理
[panel setDelegate:myDelegate];
关联策略
OBJC\u association\u RETAIN
将保留传入的对象(
myDelegate
),只要该对象与其关联(
panel
),然后将其释放

采用此解决方案可避免使委托属性本身变得强大,并允许客户端控制是否保留委托。如果您也在实现服务器,您当然可以提供一种方法来实现这一点,可能是
associatedDelegate:
?,以避免客户端需要定义密钥并调用
objc\u setAssociatedObject
本身。(也可以使用类别将其添加到现有类中。)


HTH.

这完全取决于对象的体系结构

当人们使用弱委托时,这是因为委托通常是某种“父”对象,它保留了拥有委托的对象(我们称之为“委托者”)。为什么它必须是父对象?不一定是这样;然而,在大多数用例中,它是最方便的p
#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
#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
#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];