任何人都成功使用UIView的NSProxy(例如,UILabel?)

hen*_*yaz 13 iphone calayer uiview uilabel nsproxy

我正在尝试为我的UIViews添加功能(根据状态配置CALayers),设置一个NSProxy子类代替我选择的任何UIView.这是我尝试过的:

在我的NSProxy子类中,我有以下代码:

#pragma mark Initialization / Dealloc

- (id)initWithView:(UIView *)view
{
    delegate = view;
    [delegate retain];

    return self;
}

- (void)dealloc
{
    [delegate release];
    [super dealloc];
}


#pragma mark Proxy Methods

- (void)forwardInvocation:(NSInvocation *)anInvocation
{
    [anInvocation setTarget:delegate];
    [anInvocation invoke];
    return;
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
    return [delegate methodSignatureForSelector:aSelector];
}

- (BOOL)respondsToSelector:(SEL)aSelector 
{
    BOOL rv = NO;

    if ([delegate respondsToSelector:aSelector]) { rv = YES; }

    return rv;
}
Run Code Online (Sandbox Code Playgroud)

并且,以这种方式使用我的NSProxy子类:

UILabel *label = [[HFMultiStateProxy alloc] initWithView:[[[UILabel alloc] initWithFrame:cellFrame] autorelease]];
label.text = text;
label.font = font;
label.textAlignment = UITextAlignmentCenter;
label.backgroundColor = [UIColor clearColor];
label.opaque = NO;

[self addSubview:label];
Run Code Online (Sandbox Code Playgroud)

似乎工作,直到我点击addSubview:行.

打开消息跟踪(instrumentObjcMessageSends(YES);)显示每个先前消息的转发,直到addSubview:内部,这一系列方法调用显示在日志中(此处显示的第一条消息是通过代理):

- UILabel UIView _makeSubtreePerformSelector:withObject:
- UILabel UIView _makeSubtreePerformSelector:withObject:withObject:copySublayers:
- CALayer CALayer sublayers
- NSMethodSignature NSMethodSignature methodReturnType
- NSMethodSignature NSMethodSignature _argInfo:
- NSMethodSignature NSMethodSignature _frameDescriptor
+ UILabel NSObject resolveInstanceMethod:
- UILabel NSObject forwardingTargetForSelector:
- UILabel NSObject forwardingTargetForSelector:
- UILabel NSObject methodSignatureForSelector:
- UILabel NSObject methodSignatureForSelector:
- UILabel NSObject class
- UILabel NSObject doesNotRecognizeSelector:
Run Code Online (Sandbox Code Playgroud)

我收到以下错误:

2011-02-20 16:38:52.048 FlashClass_dbg[22035:207] -[UILabel superlayer]: unrecognized selector sent to instance 0x757d470
Run Code Online (Sandbox Code Playgroud)

如果我不使用NSProxy子类而是使用UILabel子类(HFMultiStateLabel),它可以正常工作.以下是调用addSubview:时发生的消息跟踪(HFNoteNameControl是标签的超级视图):

- HFNoteNameControl UIView addSubview:
- HFNoteNameControl UIView _addSubview:positioned:relativeTo:
- HFMultiStateLabel UIView superview
- HFMultiStateLabel UIView window
- HFNoteNameControl NSObject isKindOfClass:
- HFNoteNameControl NSObject class
- HFNoteNameControl UIView window
- UIWindow NSObject isKindOfClass:
- UIWindow NSObject class
- HFNoteNameControl UIView _shouldTryPromoteDescendantToFirstResponder
- HFMultiStateLabel UIView _isAncestorOfFirstResponder
- HFMultiStateLabel UIView _willMoveToWindow:withAncestorView:
- HFMultiStateLabel UIView _willMoveToWindow:
- HFMultiStateLabel UIView willMoveToWindow:
- HFMultiStateLabel UIView _makeSubtreePerformSelector:withObject:withObject:copySublayers:
- CALayer CALayer sublayers
- HFMultiStateLabel UIView willMoveToSuperview:
- HFMultiStateLabel UIView _unsubscribeToScrollNotificationsIfNecessary:
- HFMultiStateLabel UIView _makeSubtreePerformSelector:withObject:
- HFMultiStateLabel UIView _makeSubtreePerformSelector:withObject:withObject:copySublayers:
- CALayer CALayer sublayers
- CALayer CALayer superlayer
Run Code Online (Sandbox Code Playgroud)

我可以验证在使用NSProxy时,直到-superlayer的每个方法都被成功调用.出于某种原因,使用NSProxy,UILabel上的超级层被调用而不是CALayer.也许在某个地方出现了混淆,UILabel被插入子层而不是它的CALayer?

我错过了什么吗?

UIKit是否做了某种优化,绕过了NSProxy挂钩的常规机制?

其他想法?

谢谢!

亨利

PS我只在模拟器中试过这个,而不是设备.这种行为会有所不同吗?

hen*_*yaz 3

我放弃了尝试。我得出的结论是 NSProxy 是一个未被充分利用的对象,它在 Apple 示例之外的用途尚未得到充分探索或调试。简而言之,我认为 NSProxy 还没有准备好用作扩展对象功能的通用方法,而无需子类化或添加类别。

在过去,我会使用poseAsClass调用来实现我想要的功能。

我的解决方案最终是这样的:

  • 我向 UIView 添加了一个类别,添加了其他属性。这些属性实现将它们的设置和获取消息转发到 UIView 的“addOn”属性,我也将其放入该类别中。当然,UIView 类别实现中这个“addOn”属性的默认值是 nil。(我本可以实现一个静态哈希表来为任何 UIView 关联一个 AddOn 实例,但我认为正确管理保留计数是一种危险的策略。)

  • “AddOn”类中有额外的代码来直接操作 UIView,并且它在其中添加了额外的绘图代码。

  • 对于我想要添加此附加功能的每种类型的 UIView,我必须使用以下代码对其进行子类化:a)为“AddOn”类创建实例方法和相应的属性代码 b)对我涵盖的任何函数进行子类化以给出“ AddOn”代码是添加其功能的机会。

  • 这些子类中的每一个都具有本质上相同的代码,以将所需的功能转发到 AddOn 实例。

所以,我最终尽可能地减少了代码重复,但是每个支持使用“AddOn”功能的 UIView 后代子类最终都会重复代码。

看来我可以通过使用类方法操作函数来进一步减少代码重复,但是学习曲线和代码的进一步混淆阻止了我走这条路。