NSProxy サブクラスをセットアップして、選択した UIView の代わりになるように設定することで、UIViews に機能を追加する (状態に応じて 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 はラベルのスーパービューです)。
- 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 では、CALayer の代わりに UILabel 上のスーパーレイヤーが呼び出されています。おそらくどこかで混乱し、UILabel がその CALayer の代わりにサブレイヤーに挿入されるのでしょうか?
何か不足していますか?
UIKit は、NSProxy がフックする通常のメカニズムをバイパスする何らかの最適化を行いますか?
他の考え?
ありがとう!
ヘンリー
PS私はこれをデバイスではなくシミュレータでのみ試しました。その行動は何か違うでしょうか?