bang590 / JSPatch

JSPatch bridge Objective-C and Javascript using the Objective-C runtime. You can call any Objective-C class and method in JavaScript by just including a small engine. JSPatch is generally used to hotfix iOS App.
MIT License
11.36k stars 2.24k forks source link

[UINavigationBar appearance] 这种protocol应该用js怎么写? #170

Open AthrunZala opened 8 years ago

AthrunZala commented 8 years ago

[[UINavigationBar appearance] setBackgroundImage:[UIImage imageWithColor:[UIColor whiteColor]] forBarMetrics:0];

写成 UINavigationBar.appearance().setBackgroundImage_forBarMetrics(UIImage.imageWithColor(UIColor.whiteColor()), 0);

跑起来会crash

reason: 'unrecognized selector setBackgroundImage:forBarMetrics: for instance <_UIAppearance:0x7f840a868f10> with invocations

AthrunZala commented 8 years ago

不好意思,bang590,能帮忙解答一下吗?

bang590 commented 8 years ago

这个写法没问题,会crash可能是因为apperance有特殊机制,我再研究下

AthrunZala commented 8 years ago

不知道有没有结果啊,我就是要在defineClass('NVAppDelegate', { doJobsAfterFinishLaunching: function() { UINavigationBar.appearance().setBackgroundImage_forBarMetrics(UIImage.imageWithColor(UIColor.whiteColor()), 0); }, });

设置一下uinavigationbar color.

captain-black commented 8 years ago

@bang590 UIApearance 协议确实有特殊机制. 它是把调用的方法转化成 NSInvocation 暂存, 然后对应类对象UI 刷新时调用这个 NSInvocation 来设置样式... JSPatch 现在找到办法能实现这种调用方式没?

---分割--- 经过调试UIAppearance 类. 我推断appearance 对象是通过-(void)forwardInvocation:(NSInvocation)invocation;来把对应SEL的invocation 和 类进行绑定的. 我对 UINavigationBar 的setBackgroundImage:forBarMetrics:生成了一个 NSInvocation 对象, 然后调用 appearance 的 -(void)forwardInvocation:(NSInvocation_)invocation;就能实现原生代码一样的效果了.

实现方法有点绕, 但是能绕过 JSPatch 里面找不到方法签名的问题

ColinHwang commented 8 years ago

感谢大神们提供思路, 方便后来人:

require('JPEngine').addExtensions(['JPMemory'])

var signature = require('UINavigationBar').instanceMethodSignatureForSelector("setBarTintColor:"); var invocation = require('NSInvocation').invocationWithMethodSignature(signature); var redColor = require('UIColor').redColor(); invocation.setTarget(self); invocation.setSelector("setBarTintColor:"); invocation.setArgument_atIndex(getPointer(redColor), 2); require('UINavigationBar').appearance().forwardInvocation(invocation);