gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-03 18:26:01 25 4
gpt4 key购买 nike

我正在尝试通过设置 NSProxy 子类来代替我选择的任何 UIView,向我的 UIView 添加功能(根据状态配置 CALayers)。这是我尝试过的:

在我的 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 是标签的 super View ):

- 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 上的 super 层而不是 CALayer。也许某个地方有些困惑,UILabel 被插入到子层而不是 CALayer 中?

UIKit 是否会进行某种优化来绕过 NSProxy Hook 的正常机制?

PS 我只在模拟器中尝试过此操作,而不是在设备中。这种行为会有什么不同吗?

最佳答案

当我遇到这个问题时,我试图解决同样的问题 - 将 NSProxy 与 UIView (在我的例子中为 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:...

它因无法识别的选择器异常而崩溃。

通常情况下,首先会询问对象 - (NSMethodSignature *)methodSignatureForSelector:(SEL)sel 方法,当该方法返回时,它会调用 - (void)forwardInitation:(NSInvocau) *)在代理中调用。这样我们就可以重定向消息。如果没有返回 NSMethodSignature,则在对象上调用 doesNotRecognizeSelector: 方法。因此我们甚至会收到无法识别的选择器调用。

这适用于实例方法,但此崩溃是由类方法引起的,我们对此无权控制 - 对象本身未被调用(类被调用)。我想通过覆盖我的 NSProxy 子类的 getter 来强制运行时调用我的代理类,甚至是类方法

- (Class) class
{
return _myRealClass;
}

这不起作用。所以 NSProxy 不足以做到这一点。现在我正在尝试使用 NSObject 而不是 NSProxy 来实现所有所需的行为,因为 NSObject 有 + (BOOL)resolveClassMethod:(SEL)sel 方法,这可能很有用。一旦我发现 NSObject 是否更适合于此,我将编辑这篇文章。

//编辑

问题似乎在于,使用 NSProxy 时,在 UIView 上调用 superlayer,而不是在 CALayer 上调用。

所以这看起来确实是一个 UIKit 快捷方式问题 - 他们没有发送常规消息调用(我猜是速度优化)。

无论如何,我现在正在寻找一种方法来解决这个问题。

关于iphone - 任何人都成功使用 UIView 的 NSProxy (例如 UILabel?),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5061223/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com