首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >有没有人成功使用了UIView的NSProxy (例如UILabel?)

有没有人成功使用了UIView的NSProxy (例如UILabel?)
EN

Stack Overflow用户
提问于 2011-02-21 08:35:50
回答 4查看 2.2K关注 0票数 13

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

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

代码语言:javascript
复制
#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子类:

代码语言:javascript
复制
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:的内部,日志中显示了这一系列方法调用(此处显示的第一条消息是通过代理调用的):

代码语言:javascript
复制
- 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:

我得到了以下错误:

代码语言:javascript
复制
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 )时出现的消息跟踪:

代码语言:javascript
复制
- 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我只在模拟器中尝试过,没有在设备中尝试过。这种行为会有什么不同吗?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2011-04-16 22:28:15

我放弃了尝试。我得出的结论是,NSProxy是一个未得到充分利用的对象,除了苹果的例子之外,它的潜在用途还没有得到充分的探索和调试。简而言之,我认为如果没有子类化或添加类别,NSProxy还不能用作扩展对象功能的通用方法。

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

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

  • I向UIView添加了一个类别,该类别添加了其他属性。这些属性实现将它们的set & get消息转发到UIView的"addOn“属性,我也将其放入了类别中。在UIView的category实现中,这个"addOn“属性的默认值当然是nil。(我本可以实现一个静态哈希表来为任何UIView关联一个AddOn实例,但是我觉得正确地使用retain计数来管理它是一个危险的策略。)
  • "AddOn“类中有额外的代码来直接操作UIView,并且它在其中添加了额外的绘图代码。
  • 对于我想要添加的每种类型的UIView,都添加了这个添加的功能。我必须使用以下代码对其进行子类化: a)为" AddOn“类创建一个实例方法和相应的属性代码b)对我介绍的任何函数进行子类化,以使"AddOn”代码有机会添加其functionality.
  • Each这些子类具有本质上相同的代码,以便将所需的功能转发到AddOn实例。

因此,我最终尽可能地减少了代码重复,但每个支持使用"AddOn“功能的UIView子类最终都会复制代码。

似乎我可以通过使用类方法操作函数进一步最小化代码重复,但是学习曲线和代码的进一步混淆阻止了我遵循这条道路。

票数 3
EN

Stack Overflow用户

发布于 2013-08-27 19:04:43

当我遇到这个问题时,我正试图解决同样的问题--在UIView中使用NSProxy (在我的例子中是UITableViewCell)。我记录了控制台的所有呼叫:

代码语言:javascript
复制
...
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来强制运行时调用我的代理类,甚至是类方法

代码语言:javascript
复制
- (Class) class
{
    return _myRealClass;
}

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

//编辑

问题似乎在于,在NSProxy中,调用superlayer的是UIView而不是CALayer。证据:http://t2523.codeinpro.us/q/508112244f1eba38a4fb032e

因此,这看起来真的像是一个UIKit快捷方式问题--他们不会发送常规的消息调用(我猜是速度优化)。

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

票数 4
EN

Stack Overflow用户

发布于 2011-02-21 09:59:08

我从未尝试过在视图中使用NSProxy,但我使用自定义视图类来显示另一个视图,从而完成了类似的操作。也许系统需要一个实际的视图,而不是一个代理对象。有两种方式可以使用“代理”视图:

  1. 使代理视图成为代理视图的子视图。代理将从代理视图中获取框架、自动调整大小蒙版等,然后添加代理视图作为其子视图,并将其框架设置为代理视图的边界,并将其自动调整大小掩码设置为总是填充代理视图。删除代理视图后,所有设置都将从代理视图复制回代理视图。任何未复制到代理中的属性都将被传递到代理视图,使用forwarding.
  2. The代理视图将几乎每条消息传递到代理视图。代理视图不覆盖lock/unlockFocus、display等方法。它重写drawRect:以在代理视图上调用drawRect:。
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5061223

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档