我正在尝试向我的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;
}并且,以这种方式使用我的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];在我输入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:我得到了以下错误:
2011-02-20 16:38:52.048 FlashClass_dbg[22035:207] -[UILabel superlayer]: unrecognized selector sent to instance 0x757d470如果我不使用NSProxy子类,而是使用UILabel子类(HFMultiStateLabel),它会工作得很好。下面是调用addSubview:(HFNoteNameControl是标签的superview )时出现的消息跟踪:
- 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在使用NSProxy时,我可以验证直到-superlayer的每个方法都被成功调用。由于某些原因,使用NSProxy时,调用的是UILabel上的superlayer,而不是CALayer。也许有什么地方搞错了,UILabel被插入到子层而不是它的CALayer?
我是不是遗漏了什么?
UIKit是否做了一些绕过NSProxy所连接的正常机制的优化?
其他想法?
谢谢!
亨利
PS我只在模拟器中尝试过,没有在设备中尝试过。这种行为会有什么不同吗?
发布于 2011-04-16 22:28:15
我放弃了尝试。我得出的结论是,NSProxy是一个未得到充分利用的对象,除了苹果的例子之外,它的潜在用途还没有得到充分的探索和调试。简而言之,我认为如果没有子类化或添加类别,NSProxy还不能用作扩展对象功能的通用方法。
在过去,我会使用poseAsClass调用来实现我想要的功能。
我的解决方案最终是这样的:
因此,我最终尽可能地减少了代码重复,但每个支持使用"AddOn“功能的UIView子类最终都会复制代码。
似乎我可以通过使用类方法操作函数进一步最小化代码重复,但是学习曲线和代码的进一步混淆阻止了我遵循这条道路。
发布于 2013-08-27 19:04:43
当我遇到这个问题时,我正试图解决同样的问题--在UIView中使用NSProxy (在我的例子中是UITableViewCell)。我记录了控制台的所有呼叫:
...
App[2857:c07] MyHeaderCell: --- method signature for: _unsubscribeToScrollNotificationsIfNecessary:
App[2857:c07] MyHeaderCell: --- _unsubscribeToScrollNotificationsIfNecessary:
App[2857:c07] MyHeaderCell: --- method signature for: _makeSubtreePerformSelector:withObject:
App[2857:c07] MyHeaderCell: --- _makeSubtreePerformSelector:withObject:
App[2857:c07] +[MyHeaderCell superlayer]: unrecognized selector sent to class 0x1331f8c
App[2857:c07] CRASH: +[SMSHeaderCell superlayer]: unrecognized selector sent to class 0x1331f8c
App[2857:c07] Stack Trace:...它在unrecognized selector异常时崩溃。
通常,首先向对象询问- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel方法,当该方法返回时,它将调用代理中的- (void) forwardInvocation:(NSInvocation *)invocation。这样我们就可以重定向消息了。如果没有返回NSMethodSignature,则在对象上调用doesNotRecognizeSelector:方法。所以我们甚至得到了无法识别的选择器调用。
这对于实例方法有效,但这种崩溃是由类方法引起的,我们对类方法没有权力-对象本身不被调用(类被调用)。我想通过重写我的NSProxy子类的getter来强制运行时调用我的代理类,甚至是类方法
- (Class) class
{
return _myRealClass;
}但这并不管用。因此,NSProxy不足以做到这一点。现在,我正在尝试使用NSObject而不是NSProxy来实现所有所需的行为,因为NSObject具有可能有用的+ (BOOL)resolveClassMethod:(SEL)sel方法。一旦我发现NSObject是否更适合这一点,我就会编辑这篇文章。
//编辑
问题似乎在于,在NSProxy中,调用superlayer的是UIView而不是CALayer。证据:http://t2523.codeinpro.us/q/508112244f1eba38a4fb032e
因此,这看起来真的像是一个UIKit快捷方式问题--他们不会发送常规的消息调用(我猜是速度优化)。
无论如何,我现在正在寻找一种方法来解决这个问题。
发布于 2011-02-21 09:59:08
我从未尝试过在视图中使用NSProxy,但我使用自定义视图类来显示另一个视图,从而完成了类似的操作。也许系统需要一个实际的视图,而不是一个代理对象。有两种方式可以使用“代理”视图:
https://stackoverflow.com/questions/5061223
复制相似问题