WebView
通过WebEditingDelegate
支持一种机制,该机制可使委托(delegate)人为WebView
(或私有(private)WebHTMLView
)接收的各种操作实现自定义行为。当一个 Action 如:
-(void)changeAttributes:(id)sender
以
WebHTMLView
接收,并将其传递给委托(delegate)方法:-(BOOL)webView:(WebView *)webView doCommandBySelector:(SEL)command
不幸的是,该机制没有提供原始 Action 方法中“
sender
”的传送。对于绝大多数 Action 而言,发送者并不重要,但是对于changeAttributes和changeFont,例如,契约(Contract)要求接收者调用“
sender
”,例如convertAttributes:
或convertFont:
。对于
changeFont
情况,事实证明,调用[[NSFontManager sharedFontManager] convertFont:]
就足够了,因为恰巧这就是发送方。在
changeAttributes
的情况下,尤其是当删除线被更改时,发送方可能是私有(private)类“NSFontEffectsBox
”,该类可能对应于负责更改删除线/etc设置的字体面板的小节。不幸的是,调用
[[NSFontManager sharedFontManager] convertAttributes:]
无法获得预期的属性更改。这使一个有兴趣在有意义的地方实现此方法的代表感到困惑:[sender convertAttributes:]
调用。 changeAttributes:
调用被发送到私有(private)WebKit类WebHTMLView
,该类不能被子类化,例如,自定义changeAttributes:
的行为。 changeAttributes:
调用的发送方NSFontEffectsBox
是私有(private)类,无法访问,例如作为[NSFontEffectsBox sharedFontEffectsBox]
。 简而言之:开发人员似乎没有办法有意义地覆盖
changeAttributes:
的WebView
行为。有任何想法吗?
最佳答案
这是邪恶的。一对适当的邪恶 Action (它们都不是特别干净或理想的):
%eax
进行调用时,发件人位于堆栈中,而不是放在WebHTMLView
中。但是,这将始终适用于PowerPC代码,因此可能在那里没有启动器。 WebHTMLView
之类的方法在__my_evil_hacky_nasty_ugly_changeAttributes_thing:
上放置一个类别,并在运行时使用ObjC运行时中的method_exchangeImplementations()将您类别的实现与它们的实现交换。您的方法将变成changeAttributes:
,而他们的方法将变成__my_evil_hacky_nasty_ugly_changeAttributes_thing:
,然后可以调用该方法以传递原始调用。 就像我说的那样,两者都不是特别理想,但是第二个优点是具有完整的运行时支持(即,运行时经过明确设计可以让您做到这一点),并且由于您在运行时查找类和方法,因此失败了-宽容。在这种情况下,失败会使您回到第一位。
确实,它需要针对WebKit记录一个错误,以使它们传递给发送方,以使其完全有意义。您的重写版本可能会寻找方法
-(BOOL)webView:(WebView*)webView doCommandBySelector:(SEL)selector sender:(id)sender
并在找到后调用该方法,否则只需调用原始方法即可。这是Apple的代码应做的事情,TBH。