JSPatch ÊÇÒ»¸ö iOS ¶¯Ì¬¸üпò¼Ü£¬Ö»ÐèÔÚÏîÄ¿ÖÐÒýÈ뼫СµÄÒýÇæ£¬¾Í¿ÉÒÔʹÓÃ
JavaScript µ÷ÓÃÈκΠObjective-C ÔÉú½Ó¿Ú£¬»ñµÃ½Å±¾ÓïÑÔµÄÓÅÊÆ£ºÎªÏîÄ¿¶¯Ì¬Ìí¼ÓÄ£¿é£¬»òÌæ»»ÏîÄ¿ÔÉú´úÂ붯̬ÐÞ¸´
bug¡£
֮ǰÔÚ²©¿ÍÉÏд¹ýÁ½Æª JSPatch ÔÀí½âÎöÎÄÕÂ( 1 2)£¬µ«Ëæ×Å JSPatch µÄ¸Ä½ø£¬ÓÐЩÄÚÈÝÒѾ¸ú×îдúÂë¶Ô²»ÉÏ£¬ÕâÀïÖØÐÂÕûÀí³ÉһƪÍêÕûµÄÎÄÕ£¬¶ÔÔÀ´µÄÁ½Æª×öÕûºÏºÍÐ޸ģ¬Ïêϸ²ûÊö
JSPatch µÄʵÏÖÔÀíºÍһЩϸ½Ú£¬ÒÔ°ïÖúʹÓÃÕ߸üºÃµØÁ˽âºÍʹÓà JSPatch¡£
»ù´¡ÔÀí
JSPatch ÄÜ×öµ½Í¨¹ý JS µ÷Óú͸Äд OC ·½·¨×î¸ù±¾µÄÔÒòÊÇ Objective-C ÊǶ¯Ì¬ÓïÑÔ£¬OC
ÉÏËùÓз½·¨µÄµ÷ÓÃ/ÀàµÄÉú³É¶¼Í¨¹ý Objective-C Runtime ÔÚÔËÐÐʱ½øÐУ¬ÎÒÃÇ¿ÉÒÔͨ¹ýÀàÃû/·½·¨Ãû·´ÉäµÃµ½ÏàÓ¦µÄÀàºÍ·½·¨£º
Class class = NSClassFromString("UIViewController"); id viewController = [[class alloc] init]; SEL selector = NSSelectorFromString("viewDidLoad"); [viewController performSelector:selector]; |
Ò²¿ÉÒÔÌæ»»Ä³¸öÀàµÄ·½·¨ÎªÐµÄʵÏÖ£º
static void newViewDidLoad(id slf, SEL sel) {} class_replaceMethod(class, selector, newViewDidLoad, @""); ; |
»¹¿ÉÒÔÐÂ×¢²áÒ»¸öÀ࣬ΪÀàÌí¼Ó·½·¨£º
Class cls = objc_allocateClassPair(superCls, "JPObject", 0); objc_registerClassPair(cls); class_addMethod(cls, selector, implement, typedesc); |
¶ÔÓÚ Objective-C ¶ÔÏóÄ£ÐͺͶ¯Ì¬ÏûÏ¢·¢Ë͵ÄÔÀíÒÑÓкܶàÎÄÕ²ûÊöµÃºÜÏêϸ£¬ÕâÀï¾Í²»Ïêϸ²ûÊöÁË¡£ÀíÂÛÉÏÄã¿ÉÒÔÔÚÔËÐÐʱͨ¹ýÀàÃû/·½·¨Ãûµ÷Óõ½ÈκÎ
OC ·½·¨£¬Ìæ»»ÈκÎÀàµÄʵÏÖÒÔ¼°ÐÂÔöÈÎÒâÀà¡£ËùÒÔ JSPatch µÄ»ù±¾ÔÀí¾ÍÊÇ£ºJS ´«µÝ×Ö·û´®¸ø OC£¬OC
ͨ¹ý Runtime ½Ó¿Úµ÷ÓúÍÌæ»» OC ·½·¨¡£ÕâÊÇ×î»ù´¡µÄÔÀí£¬Êµ¼ÊʵÏÖ¹ý³Ì»¹Óкܶà¹ÖÒª´ò£¬½ÓÏÂÀ´¿´¿´¾ßÌåÊÇÔõÑùʵÏֵġ£
·½·¨µ÷ÓÃ
require('UIView') var view = UIView.alloc().init() view.setBackgroundColor(require('UIColor').grayColor()) view.setAlpha(0.5) |
ÒýÈë JSPatch ºó£¬¿ÉÒÔͨ¹ýÒÔÉÏ JS ´úÂë´´½¨ÁËÒ»¸ö UIView ʵÀý£¬²¢ÉèÖñ³¾°ÑÕÉ«ºÍ͸Ã÷¶È£¬º¸ÇÁË
require ÒýÈëÀ࣬JS µ÷Óýӿڣ¬ÏûÏ¢´«µÝ£¬¶ÔÏó³ÖÓкÍת»»£¬²ÎÊýת»»ÕâÎå¸ö·½Ã棬½ÓÏÂÀ´ÖðÒ»¿´¿´¾ßÌåʵÏÖ¡£
1. require
µ÷Óà require('UIView') ºó£¬¾Í¿ÉÒÔÖ±½ÓʹÓà UIView Õâ¸ö±äÁ¿È¥µ÷ÓÃÏàÓ¦µÄÀà·½·¨ÁË£¬require
×öµÄʺܼòµ¥£¬¾ÍÊÇÔÚJSÈ«¾Ö×÷ÓÃÓòÉÏ´´½¨Ò»¸öͬÃû±äÁ¿£¬±äÁ¿Ö¸ÏòÒ»¸ö¶ÔÏ󣬶ÔÏóÊôÐÔ__isCls±íÃ÷ÕâÊÇÒ»¸öClass£¬__clsName±£´æÀàÃû£¬ÔÚµ÷Ó÷½·¨Ê±»áÓõ½ÕâÁ½¸öÊôÐÔ¡£
var _require = function(clsName) { if (!global[clsName]) { global[clsName] = { __isCls: 1, __clsName: clsName } } return global[clsName] } |
ËùÒÔµ÷Óà require('UIView') ºó£¬¾ÍÔÚÈ«¾Ö×÷ÓÃÓòÉú³ÉÁË UIView Õâ¸ö±äÁ¿£¬Ö¸ÏòÒ»¸öÕâÑùÒ»¸ö¶ÔÏó£º
{ __isCls: 1, __clsName: "UIView" } ! |
2. JS½Ó¿Ú
½ÓÏÂÀ´¿´¿´ UIView.alloc() ÊÇÔõÑùµ÷Óõġ£
i. ·â×° JS ¶ÔÏó
¶ÔÓÚÕâ¸öµ÷ÓõÄʵÏÖ£¬Ò»¿ªÊ¼ÎÒµÄÏë·¨ÊÇ£¬¸ù¾ÝJSÌØÐÔ£¬ÈôÒªÈà UIView.alloc() Õâ¾äµ÷Óò»³ö´í£¬Î¨Ò»µÄ·½·¨¾ÍÊǸø
UIView Õâ¸ö¶ÔÏóÌí¼Ó alloc ·½·¨£¬²»È»ÊDz»¿ÉÄܵ÷Óóɹ¦µÄ£¬JS ¶ÔÓÚµ÷ÓÃû¶¨ÒåµÄÊôÐÔ/±äÁ¿£¬Ö»»áÂíÉÏÅ׳öÒì³££¬¶ø²»Ïñ
OC/Lua/Ruby ÄÇÑù»áÓÐת·¢»úÖÆ¡£ËùÒÔ×öÁËÒ»¸ö¸´ÔÓµÄÊ£¬¾ÍÊÇÔÚRequireÉú³ÉÀà¶ÔÏóʱ£¬°ÑÀàÃû´«ÈëOC£¬OC
ͨ¹ýRuntime·½·¨ÕÒ³öÕâ¸öÀàËùÓеķ½·¨·µ»Ø¸ø JS£¬JS Àà¶ÔÏóΪÿ¸ö·½·¨Ãû¶¼Éú³ÉÒ»¸öº¯Êý£¬º¯ÊýÄÚÈݾÍÊÇÄÃ×Å·½·¨ÃûÈ¥
OC µ÷ÓÃÏàÓ¦·½·¨¡£Éú³ÉµÄ UIView ¶ÔÏó´óÖÂÊÇÕâÑùµÄ£º
{ __isCls: 1, __clsName: "UIView", alloc: function() {¡}, beginAnimations_context: function() {¡}, setAnimationsEnabled: function(){¡}, ... } |
ʵ¼ÊÉϲ»½öÒª±éÀúµ±Ç°ÀàµÄËùÓз½·¨£¬»¹ÒªÑ»·ÕÒ¸¸ÀàµÄ·½·¨Ö±µ½¶¥²ã£¬Õû¸ö¼Ì³ÐÁ´ÉϵÄËùÓз½·¨¶¼Òª¼Óµ½JS¶ÔÏóÉÏ£¬Ò»¸öÀà¾ÍÓм¸°Ù¸ö·½·¨£¬ÕâÑù°Ñ·½·¨È«²¿¼Óµ½
JS ¶ÔÏóÉÏ£¬Åöµ½ÁËͦÑÏÖØµÄÎÊÌ⣬ÒýÈ뼸¸öÀà¾ÍÄڴ汩ÕÇ£¬ÎÞ·¨Ê¹Ó᣺óÀ´ÎªÁËÓÅ»¯ÄÚ´æÎÊÌ⻹ÔÚ JS ¸ãÁ˼̳йØÏµ£¬²»°Ñ¼Ì³ÐÁ´ÉÏËùÓз½·¨¶¼Ìí¼Óµ½Ò»¸öJS¶ÔÏ󣬱ÜÃâÏñ»ùÀà
NSObject µÄ¼¸°Ù¸ö·½·¨·´¸´Ìí¼ÓÔÚÿ¸ö JS ¶ÔÏóÉÏ£¬Ã¿¸ö·½·¨Ö»´æÔÚÒ»·Ý£¬JS ¶ÔÏó¸´ÖÆÁË OC
¶ÔÏóµÄ¼Ì³Ð¹ØÏµ£¬ÕÒ·½·¨Ê±ÑØ×ż̳ÐÁ´ÍùÉÏÕÒ£¬½á¹ûÄÚ´æÏûºÄÊÇСÁËһЩ£¬µ«»¹ÊÇ´óµ½ÄÑÒÔ½ÓÊÜ¡£
ii. __c()Ôªº¯Êý
µ±Ê±¼ÌÐø¿à¿àѰÕÒ½â¾ö·½°¸£¬Èô°´ JS Óï·¨£¬ÕâÊÇΨһµÄ·½·¨£¬µ«Èô²»°´ JS Óï·¨ÄØ£¿Í»È»ÄÔ¶´¿ªÁËÏ£¬CoffieScript/JSX
¶¼¿ÉÒÔÓà JS ʵÏÖÒ»¸ö½âÊÍÆ÷ʵÏÖ×Ô¼ºµÄÓï·¨£¬ÎÒÒ²¿ÉÒÔͨ¹ýÀàËÆµÄ·½Ê½×öµ½£¬ÔÙ½øÒ»²½Ïëµ½ÆäʵÎÒÏëÒªµÄЧ¹ûºÜ¼òµ¥£¬¾ÍÊǵ÷ÓÃÒ»¸ö²»´æÔÚ·½·¨Ê±£¬ÄÜת·¢µ½Ò»¸öÖ¸¶¨º¯ÊýÈ¥Ö´ÐУ¬¾ÍÄܽâ¾öÒ»ÇÐÎÊÌâÁË£¬ÕâÆäʵ¿ÉÒÔÓüòµ¥µÄ×Ö·û´®Ìæ»»£¬°Ñ
JS ½Å±¾ÀïµÄ·½·¨µ÷Óö¼Ìæ»»µô¡£×îºóµÄ½â¾ö·½°¸ÊÇ£¬ÔÚ OC Ö´ÐÐ JS ½Å±¾Ç°£¬Í¨¹ýÕýÔò°ÑËùÓз½·¨µ÷Óö¼¸Ä³Éµ÷ÓÃ
__c() º¯Êý£¬ÔÙÖ´ÐÐÕâ¸ö JS ½Å±¾£¬×öµ½ÁËÀàËÆ OC/Lua/Ruby µÈµÄÏûϢת·¢»úÖÆ£º
UIView.alloc().init() -> UIView.__c('alloc')().__c('init')() |
¸ø JS ¶ÔÏó»ùÀà Object µÄ prototype ¼ÓÉÏ __c ³ÉÔ±£¬ÕâÑùËùÓжÔÏ󶼿ÉÒÔµ÷Óõ½
__c£¬¸ù¾Ýµ±Ç°¶ÔÏóÀàÐÍÅжϽøÐв»Í¬²Ù×÷£º
Object.prototype.__c = function(methodName) { if (!this.__obj && !this.__clsName) return this[methodName].bind(this); var self = this return function(){ var args = Array.prototype.slice.call(arguments) return _methodFunc(self.__obj, self.__clsName, methodName, args, self.__isSuper) } } |
_methodFunc() ¾ÍÊǰÑÏà¹ØÐÅÏ¢´«¸øOC£¬OCÓà Runtime ½Ó¿Úµ÷ÓÃÏàÓ¦·½·¨£¬·µ»Ø½á¹ûÖµ£¬Õâ¸öµ÷ÓþͽáÊøÁË¡£
ÕâÑù×ö²»ÓÃÈ¥ OC ±éÀú¶ÔÏó·½·¨£¬²»ÓÃÔÚ JS ¶ÔÏó±£´æÕâЩ·½·¨£¬ÄÚ´æÏûºÄÖ±½µ 99%£¬ÕâÒ»²½ÊÇ×öÕâ¸öÏîÄ¿×îˬµÄʱºò£¬ÓÃÒ»¸ö·Ç³£¼òµ¥µÄ·½·¨½â¾öÁËÑÏÖØµÄÎÊÌâ£¬Ìæ»»Ö®Ç°ÓÖ¸´ÔÓЧ¹ûÓÖ²îµÄʵÏÖ¡£
3.ÏûÏ¢´«µÝ
½â¾öÁË JS ½Ó¿ÚÎÊÌ⣬½ÓÏÂÀ´¿´¿´ JS ºÍ OC ÊÇÔõÑù»¥´«ÏûÏ¢µÄ¡£ÕâÀïÓõ½ÁË JavaScriptCore
µÄ½Ó¿Ú£¬OC ¶ËÔÚÆô¶¯ JSPatch ÒýÇæÊ±»á´´½¨Ò»¸ö JSContext ʵÀý£¬JSContext
ÊÇ JS ´úÂëµÄÖ´Ðл·¾³£¬¿ÉÒÔ¸ø JSContext Ìí¼Ó·½·¨£¬JS ¾Í¿ÉÒÔÖ±½Óµ÷ÓÃÕâ¸ö·½·¨£º
JSContext *context = [[JSContext alloc] init]; context[@"hello"] = ^(NSString *msg) { NSLog(@"hello %@", msg); }; [_context evaluateScript:@"hello('word')"]; //output hello word |
JS ͨ¹ýµ÷Óà JSContext ¶¨ÒåµÄ·½·¨°ÑÊý¾Ý´«¸ø OC£¬OC ͨ¹ý·µ»ØÖµ´«»á¸ø JS¡£µ÷ÓÃÕâÖÖ·½·¨£¬ËüµÄ²ÎÊý/·µ»ØÖµ
JavaScriptCore ¶¼»á×Ô¶¯×ª»»£¬OC ÀïµÄ NSArray, NSDictionary, NSString,
NSNumber, NSBlock »á·Ö±ðתΪJS¶ËµÄÊý×é/¶ÔÏó/×Ö·û´®/Êý×Ö/º¯ÊýÀàÐÍ¡£ÉÏÊö _methodFunc
·½·¨¾ÍÊÇÕâÑù°ÑÒªµ÷ÓõÄÀàÃûºÍ·½·¨Ãû´«µÝ¸ø OC µÄ¡£
4.¶ÔÏó³ÖÓÐ/ת»»
½áºÏÉÏÊö¼¸µã£¬¿ÉÒÔÖªµÀ UIView.alloc() Õâ¸öÀà·½·¨µ÷ÓÃÓï¾äÊÇÔõÑùÖ´Ðеģº
a.require('UIView') Õâ¾ä»°ÔÚ JS È«¾Ö×÷ÓÃÓòÉú³ÉÁË UIView Õâ¸ö¶ÔÏó£¬ËüÓиöÊôÐÔ½Ð
__isCls£¬±íʾÕâ´ú±íÒ»¸ö OC Àà¡£
b.µ÷Óà UIView Õâ¸ö¶ÔÏóµÄ alloc() ·½·¨£¬»áÈ¥µ½ __c() º¯Êý£¬ÔÚÕâ¸öº¯ÊýÀïÅжϵ½µ÷ÓÃÕß
__isCls ÊôÐÔ£¬ÖªµÀËüÊÇ´ú±í OC À࣬°Ñ·½·¨ÃûºÍÀàÃû´«µÝ¸ø OC Íê³Éµ÷Óá£
µ÷ÓÃÀà·½·¨¹ý³ÌÊÇÕâÑù£¬ÄÇʵÀý·½·¨ÄØ£¿UIView.alloc() »á·µ»ØÒ»¸ö UIView ʵÀý¶ÔÏó¸ø
JS£¬Õâ¸ö OC ʵÀý¶ÔÏóÔÚ JS ÊÇÔõÑù±íʾµÄ£¿ÔõÑù¿ÉÒÔÔÚ JS Äõ½Õâ¸öʵÀý¶ÔÏóºó¿ÉÒÔÖ±½Óµ÷ÓÃËüµÄʵÀý·½·¨
UIView.alloc().init()£¿
¶ÔÓÚÒ»¸ö×Ô¶¨Òåid¶ÔÏó£¬JavaScriptCore »á°ÑÕâ¸ö×Ô¶¨Òå¶ÔÏóµÄÖ¸Õë´«¸ø JS£¬Õâ¸ö¶ÔÏóÔÚ
JS ÎÞ·¨Ê¹Ó㬵«Ôڻش«¸ø OC ʱ OC ¿ÉÒÔÕÒµ½Õâ¸ö¶ÔÏó¡£¶ÔÓÚÕâ¸ö¶ÔÏóÉúÃüÖÜÆÚµÄ¹ÜÀí£¬°´ÎÒµÄÀí½âÈç¹ûJSÓбäÁ¿ÒýÓÃʱ£¬Õâ¸ö
OC ¶ÔÏóÒýÓüÆÊý¾Í¼Ó1 £¬JS ±äÁ¿µÄÒýÓÃÊÍ·ÅÁ˾ͼõ1£¬Èç¹û OC ÉÏû±ðµÄ³ÖÓÐÕߣ¬Õâ¸öOC¶ÔÏóµÄÉúÃüÖÜÆÚ¾Í¸ú×Å
JS ×ßÁË£¬»áÔÚ JS ½øÐÐÀ¬»ø»ØÊÕʱÊÍ·Å¡£
´«»Ø¸ø JS µÄ±äÁ¿ÊÇÕâ¸ö OC ¶ÔÏóµÄÖ¸Õ룬Õâ¸öÖ¸ÕëÒ²¿ÉÒÔÖØÐ´«»Ø OC£¬ÒªÔÚ JS µ÷ÓÃÕâ¸ö¶ÔÏóµÄij¸öʵÀý·½·¨£¬¸ù¾ÝµÚ2µã
JS ½Ó¿ÚµÄÃèÊö£¬Ö»ÐèÔÚ __c() º¯ÊýÀï°ÑÕâ¸ö¶ÔÏóÖ¸ÕëÒÔ¼°ËüÒªµ÷Óõķ½·¨Ãû´«»Ø¸ø OC ¾ÍÐÐÁË£¬ÏÖÔÚÎÊÌâֻʣÏ£ºÔõÑùÔÚ
__c() º¯ÊýÀïÅжϵ÷ÓÃÕßÊÇÒ»¸ö OC ¶ÔÏóÖ¸Õ룿
ĿǰûÕÒµ½·½·¨ÅжÏÒ»¸ö JS ¶ÔÏóÊÇ·ñ±íʾ OC Ö¸Õ룬ÕâÀïµÄ½â¾ö·½·¨ÊÇÔÚ OC °Ñ¶ÔÏ󷵻ظø JS
֮ǰ£¬ÏȰÑËü°ü×°³ÉÒ»¸ö NSDictionary£º
static NSDictionary *_wrapObj(id obj) { return @{@"__obj": obj}; } ! |
Èà OC ¶ÔÏó×÷ΪÕâ¸ö NSDictionary µÄÒ»¸öÖµ£¬ÕâÑùÔÚ JS ÀïÕâ¸ö¶ÔÏó¾Í±ä³É£º
{__obj: [OC Object ¶ÔÏóÖ¸Õë]} |
ÕâÑù¾Í¿ÉÒÔͨ¹ýÅж϶ÔÏóÊÇ·ñÓÐ __obj ÊôÐÔµÃÖªÕâ¸ö¶ÔÏóÊÇ·ñ±íʾ OC ¶ÔÏóÖ¸Õ룬ÔÚ __c º¯ÊýÀïÈôÅжϵ½µ÷ÓÃÕßÓÐ
__obj ÊôÐÔ£¬È¡³öÕâ¸öÊôÐÔ£¬¸úµ÷ÓõÄʵÀý·½·¨Ò»Æð´«»Ø¸ø OC£¬¾ÍÍê³ÉÁËʵÀý·½·¨µÄµ÷Óá£
5.ÀàÐÍת»»
JS °ÑÒªµ÷ÓõÄÀàÃû/·½·¨Ãû/¶ÔÏ󴫸ø OC ºó£¬OC µ÷ÓÃÀà/¶ÔÏóÏàÓ¦µÄ·½·¨ÊÇͨ¹ý NSInvocation
ʵÏÖ£¬ÒªÄÜ˳Àûµ÷Óõ½·½·¨²¢È¡µÃ·µ»ØÖµ£¬Òª×öÁ½¼þÊ£º
a.È¡µÃÒªµ÷ÓÃµÄ OC ·½·¨¸÷²ÎÊýÀàÐÍ£¬°Ñ JS ´«À´µÄ¶ÔÏóתΪҪÇóµÄÀàÐͽøÐе÷Óᣠb.¸ù¾Ý·µ»ØÖµÀàÐÍÈ¡³ö·µ»ØÖµ£¬°üװΪ¶ÔÏ󴫻ظø
JS¡£
ÀýÈ翪ͷÀý× view.setAlpha(0.5)£¬ JS´«µÝ¸øOCµÄÊÇÒ»¸ö NSNumber£¬OC
ÐèҪͨ¹ýÒªµ÷Óà OC ·½·¨µÄ NSMethodSignature µÃÖªÕâÀï²ÎÊýÒªµÄÊÇÒ»¸ö float ÀàÐÍÖµ£¬ÓÚÊǰÑ
NSNumber תΪ float ÖµÔÙ×÷Ϊ²ÎÊý½øÐÐ OC ·½·¨µ÷Óá£ÕâÀïÖ÷Òª´¦ÀíÁË int/float/bool
µÈÊýÖµÀàÐÍ£¬²¢¶Ô CGRect/CGRange µÈÀàÐͽøÐÐÁËÌØÊâת»»´¦Àí£¬Ê£ÏµľÍÊÇʵÏÖϸ½ÚÁË¡£
·½·¨Ìæ»»
JSPatch ¿ÉÒÔÓà defineClass ½Ó¿ÚÈÎÒâÌæ»»Ò»¸öÀàµÄ·½·¨£¬·½·¨Ìæ»»µÄʵÏÖ¹ý³ÌÒ²ÊÇÆÄΪÇúÕÛ£¬Ò»¿ªÊ¼ÊÇÓÃ
va_list µÄ·½Ê½»ñÈ¡²ÎÊý£¬½á¹û·¢ÏÖ arm64 ϲ»¿ÉÓã¬Ö»ÄÜת¶øÓÃÁíÒ»ÖÖ hack ·½Ê½ÈƵÀʵÏÖ¡£ÁíÍâÔÚ¸øÀàÐÂÔö·½·¨¡¢ÊµÏÖproperty¡¢Ö§³Öself/super¹Ø¼ü×ÖÉÏÒ²·ÑÁËЩ¹¦·ò£¬ÏÂÃæÖð¸ö˵Ã÷¡£
1.»ù´¡ÔÀí
OCÉÏ£¬Ã¿¸öÀà¶¼ÊÇÕâÑùÒ»¸ö½á¹¹Ì壺
struct objc_class { struct objc_class * isa; const char *name; ¡. struct objc_method_list **methodLists; /*·½·¨Á´±í*/ }; |
ÆäÖÐ methodList ·½·¨Á´±íÀï´æ´¢µÄÊÇ Method ÀàÐÍ£º
typedef struct objc_method *Method; typedef struct objc_ method { SEL method_name; char *method_types; IMP method_imp; }; |
Method ±£´æÁËÒ»¸ö·½·¨µÄÈ«²¿ÐÅÏ¢£¬°üÀ¨ SEL ·½·¨Ãû£¬type ¸÷²ÎÊýºÍ·µ»ØÖµÀàÐÍ£¬IMP ¸Ã·½·¨¾ßÌåʵÏֵĺ¯ÊýÖ¸Õë¡£
ͨ¹ý Selector µ÷Ó÷½·¨Ê±£¬»á´Ó methodList Á´±íÀïÕÒµ½¶ÔÓ¦Method½øÐе÷Óã¬Õâ¸ö
methodList ÉϵÄÔªËØÊÇ¿ÉÒÔ¶¯Ì¬Ìæ»»µÄ£¬¿ÉÒÔ°Ñij¸ö Selector ¶ÔÓ¦µÄº¯ÊýÖ¸ÕëIMPÌæ»»³Éеģ¬Ò²¿ÉÒÔÄõ½ÒÑÓеÄij¸ö
Selector ¶ÔÓ¦µÄº¯ÊýÖ¸ÕëIMP£¬ÈÃÁíÒ»¸ö Selector ¸úËü¶ÔÓ¦£¬Runtime ÌṩÁËһЩ½Ó¿Ú×öÕâЩÊ£¬ÒÔÌæ»»
UIViewController µÄ -viewDidLoad: ·½·¨ÎªÀý£º
static void viewDidLoadIMP (id slf, SEL sel) { JSValue *jsFunction = ¡; [jsFunction callWithArguments:nil]; } Class cls = NSClassFromString(@"UIViewController"); SEL selector = @selector(viewDidLoad); Method method = class_getInstanceMethod(cls, selector); //»ñµÃviewDidLoad·½·¨µÄº¯ÊýÖ¸Õë IMP imp = method_getImplementation(method) //»ñµÃviewDidLoad·½·¨µÄ²ÎÊýÀàÐÍ char *typeDescription = (char *)method_getTypeEncoding(method); //ÐÂÔöÒ»¸öORIGViewDidLoad·½·¨£¬Ö¸ÏòÔÀ´µÄviewDidLoadʵÏÖ class_addMethod(cls, @selector(ORIGViewDidLoad), imp, typeDescription); //°ÑviewDidLoad IMPÖ¸Ïò×Ô¶¨ÒåеÄʵÏÖ class_replaceMethod(cls, selector, viewDidLoadIMP, typeDescription); |
ÕâÑù¾Í°Ñ UIViewController µÄ -viewDidLoad ·½·¨¸øÌæ»»³ÉÎÒÃÇ×Ô¶¨ÒåµÄ·½·¨£¬APPÀïµ÷ÓÃ
UIViewController µÄ viewDidLoad ·½·¨¶¼»áÈ¥µ½ÉÏÊö viewDidLoadIMP
º¯ÊýÀÔÚÕâ¸öеÄIMPº¯ÊýÀïµ÷Óà JS ´«½øÀ´µÄ·½·¨£¬¾ÍʵÏÖÁËÌæ»» viewDidLoad ·½·¨ÎªJS´úÂëÀïµÄʵÏÖ£¬Í¬Ê±Îª
UIViewController ÐÂÔöÁ˸ö·½·¨ -ORIGViewDidLoad Ö¸ÏòÔÀ´ viewDidLoad
µÄ IMP£¬JS ¿ÉÒÔͨ¹ýÕâ¸ö·½·¨µ÷Óõ½ÔÀ´µÄʵÏÖ¡£
·½·¨Ìæ»»¾ÍÕâÑùºÜ¼òµ¥µÄʵÏÖÁË£¬µ«Õâô¼òµ¥µÄǰÌáÊÇ£¬Õâ¸ö·½·¨Ã»ÓвÎÊý¡£Èç¹ûÕâ¸ö·½·¨ÓвÎÊý£¬ÔõÑù°Ñ²ÎÊýÖµ´«¸øÎÒÃÇеÄ
IMP º¯ÊýÄØ£¿ÀýÈç UIViewController µÄ -viewDidAppear: ·½·¨£¬µ÷ÓÃÕ߻ᴫһ¸ö
Bool Öµ£¬ÎÒÃÇÐèÒªÔÚ×Ô¼ºÊµÏÖµÄIMP£¨ÉÏÊöµÄ viewDidLoadIMP£©ÉÏÄõ½Õâ¸öÖµ£¬ÔõÑùÄÜÄõ½£¿Èç¹ûÖ»ÊÇÕë¶ÔÒ»¸ö·½·¨Ð´
IMP£¬ÊÇ¿ÉÒÔÖ±½ÓÄõ½Õâ¸ö²ÎÊýÖµµÄ£º
static void viewDidAppear (id slf, SEL sel, BOOL animated) { [function callWithArguments:@(animated)]; } |
µ«ÎÒÃÇÒªµÄÊÇʵÏÖÒ»¸öͨÓõÄIMP£¬ÈÎÒâ·½·¨ÈÎÒâ²ÎÊý¶¼¿ÉÒÔͨ¹ýÕâ¸öIMPÖÐת£¬Äõ½·½·¨µÄËùÓвÎÊý»Øµ÷JSµÄʵÏÖ¡£
2.va_listʵÏÖ(32λ)
×î³õÎÒÊÇÓÿɱä²ÎÊý va_list ʵÏÖ£º
static void commonIMP(id slf, ...) va_list args; va_start(args, slf); NSMutableArray *list = [[NSMutableArray alloc] init]; NSMethodSignature *methodSignature = [cls instanceMethodSignatureForSelector:selector]; NSUInteger numberOfArguments = methodSignature.numberOfArguments; id obj; for (NSUInteger i = 2; i < numberOfArguments; i++) { const char *argumentType = [methodSignature getArgumentTypeAtIndex:i]; switch(argumentType[0]) { case 'i': obj = @(va_arg(args, int)); break; case 'B': obj = @(va_arg(args, BOOL)); break; case 'f': case 'd': obj = @(va_arg(args, double)); break; ¡¡ //ÆäËûÊýÖµÀàÐÍ default: { obj = va_arg(args, id); break; } } [list addObject:obj]; } va_end(args); [function callWithArguments:list]; } |
ÕâÑùÎÞÂÛ·½·¨²ÎÊýÊÇʲô£¬ÓжàÉÙ¸ö£¬¶¼¿ÉÒÔͨ¹ý va_listµÄÒ»×é·½·¨Ò»¸ö¸öÈ¡³öÀ´£¬×é³É NSArray
ÔÚµ÷Óà JS ·½·¨Ê±´«»Ø¡£ºÜÍêÃÀµØ½â¾öÁ˲ÎÊýµÄÎÊÌ⣬һֱÔËÐÐÕý³££¬Ö±µ½ÎÒÅÜÔÚ arm64 µÄ»ú×ÓÉϲâÊÔ£¬Ò»µ÷ÓþÍ
crash¡£²éÁË×ÊÁÏ£¬²Å·¢ÏÖ arm64 Ï va_list µÄ½á¹¹¸Ä±äÁË£¬µ¼ÖÂÎÞ·¨ÉÏÊöÕâÑùÈ¡²ÎÊý¡£Ïê¼ûÕâÆªÎÄÕ£ºhttps://blog.nelhage.com/2010/10/amd64-and-va_arg¡£
3.ForwardInvocationʵÏÖ(64λ)
¼ÌÐøÑ°ÕÒ½â¾ö·½°¸£¬×îºóÕÒµ½ÁíÒ»Öַdz£ hack µÄ·½·¨½â¾ö²ÎÊý»ñÈ¡µÄÎÊÌ⣬ÀûÓÃÁË OC ÏûϢת·¢»úÖÆ¡£
µ±µ÷ÓÃÒ»¸ö NSObject ¶ÔÏó²»´æÔڵķ½·¨Ê±£¬²¢²»»áÂíÉÏÅ׳öÒì³££¬¶øÊǻᾹý¶à²ãת·¢£¬²ã²ãµ÷ÓöÔÏóµÄ
-resolveInstanceMethod:, -forwardingTargetForSelector:,
-methodSignatureForSelector:, -forwardInvocation: µÈ·½·¨£¬ÆäÖÐ×îºó
-forwardInvocation: ÊÇ»áÓÐÒ»¸ö NSInvocation ¶ÔÏó£¬Õâ¸ö NSInvocation
¶ÔÏó±£´æÁËÕâ¸ö·½·¨µ÷ÓõÄËùÓÐÐÅÏ¢£¬°üÀ¨ Selector Ãû£¬²ÎÊýºÍ·µ»ØÖµÀàÐÍ£¬×îÖØÒªµÄÊÇÓÐËùÓвÎÊýÖµ£¬¿ÉÒÔ´ÓÕâ¸ö
NSInvocation ¶ÔÏóÀïÄõ½µ÷ÓõÄËùÓвÎÊýÖµ¡£ÎÒÃÇ¿ÉÒÔÏë°ì·¨ÈÃÿ¸öÐèÒª±» JS Ìæ»»µÄ·½·¨µ÷ÓÃ×îºó¶¼µ÷µ½
-forwardInvocation:£¬¾Í¿ÉÒÔ½â¾öÎÞ·¨Äõ½²ÎÊýÖµµÄÎÊÌâÁË¡£
¾ßÌåʵÏÖ£¬ÒÔÌæ»» UIViewController µÄ -viewWillAppear: ·½·¨ÎªÀý£º
°ÑUIViewControllerµÄ -viewWillAppear: ·½·¨Í¨¹ý class_replaceMethod()
½Ó¿ÚÖ¸Ïò _objc_msgForward£¬ÕâÊÇÒ»¸öÈ«¾Ö IMP£¬OC µ÷Ó÷½·¨²»´æÔÚʱ¶¼»áת·¢µ½Õâ¸ö
IMP ÉÏ£¬ÕâÀïÖ±½Ó°Ñ·½·¨Ìæ»»³ÉÕâ¸ö IMP£¬ÕâÑùµ÷ÓÃÕâ¸ö·½·¨Ê±¾Í»á×ßµ½ -forwardInvocation:¡£
ΪUIViewControllerÌí¼Ó -ORIGviewWillAppear: ºÍ -_JPviewWillAppear:
Á½¸ö·½·¨£¬Ç°ÕßÖ¸ÏòÔÀ´µÄIMPʵÏÖ£¬ºóÕßÊÇеÄʵÏÖ£¬ÉÔºó»áÔÚÕâ¸öʵÏÖÀï»Øµ÷JSº¯Êý¡£
¸ÄдUIViewControllerµÄ -forwardInvocation: ·½·¨Îª×Ô¶¨ÒåʵÏÖ¡£Ò»µ©OCÀïµ÷ÓÃ
UIViewController µÄ -viewWillAppear: ·½·¨£¬¾¹ýÉÏÃæµÄ´¦Àí»á°ÑÕâ¸öµ÷ÓÃת·¢µ½
-forwardInvocation: £¬ÕâʱÒѾ×é×°ºÃÁËÒ»¸ö NSInvocation£¬°üº¬ÁËÕâ¸öµ÷ÓõIJÎÊý¡£ÔÚÕâÀï°Ñ²ÎÊý´Ó
NSInvocation ·´½â³öÀ´£¬´ø×ŲÎÊýµ÷ÓÃÉÏÊöÐÂÔö¼ÓµÄ·½·¨ -JPviewWillAppear:
£¬ÔÚÕâ¸öз½·¨ÀïÈ¡µ½²ÎÊý´«¸øJS£¬µ÷ÓÃJSµÄʵÏÖº¯Êý¡£Õû¸öµ÷Óõ÷Óùý³Ì¾Í½áÊøÁË£¬Õû¸ö¹ý³ÌͼʾÈçÏ£º

×îºóÒ»¸öÎÊÌ⣬ÎÒÃÇ°Ñ UIViewController µÄ -forwardInvocation: ·½·¨µÄʵÏÖ¸øÌæ»»µôÁË£¬Èç¹û³ÌÐòÀïÕæÓÐÓõ½Õâ¸ö·½·¨¶ÔÏûÏ¢½øÐÐת·¢£¬ÔÀ´µÄÂß¼Ôõô°ì£¿Ê×ÏÈÎÒÃÇÔÚÌæ»»
-forwardInvocation: ·½·¨Ç°»áн¨Ò»¸ö·½·¨ -ORIGforwardInvocation:£¬±£´æÔÀ´µÄʵÏÖIMP£¬ÔÚеÄ
-forwardInvocation: ʵÏÖÀï×öÁ˸öÅжϣ¬Èç¹ûת·¢µÄ·½·¨ÊÇÎÒÃÇÏë¸ÄдµÄ£¬¾Í×ßÎÒÃǵÄÂß¼£¬Èô²»ÊÇ£¬¾Íµ÷
-ORIGforwardInvocation: ×ßÔÀ´µÄÁ÷³Ì¡£
ÆäËû¾ÍÊÇʵÏÖÉϵÄϸ½ÚÁË£¬ÀýÈçÐèÒª¸ù¾Ý²»Í¬µÄ·µ»ØÖµÀàÐÍÉú³É²»Í¬µÄ IMP£¬ÒªÔÚ¸÷´¦´¦Àí²ÎÊýת»»µÈ¡£
4. ÐÂÔö·½·¨
i. ·½°¸
ÔÚ JSPatch ¸Õ¿ªÔ´Ê±£¬ÊDz»Ö§³ÖΪһ¸öÀàÐÂÔö·½·¨µÄ£¬ÒòΪ¾õµÃÄÜÌæ»»ÔÉú·½·¨¾Í¹»ÁË£¬Ðµķ½·¨´¿´âÌí¼ÓÔÚ
JS ¶ÔÏóÉÏ£¬Ö»ÔÚ JS ¶ËÅܾÍÐÐÁË¡£ÁíÍâ OC ΪÀàÐÂÔö·½·¨ÐèÒªÖªµÀ¸÷¸ö²ÎÊýºÍ·µ»ØÖµµÄÀàÐÍ£¬ÐèÒªÔÚ JS
¶¨Ò»ÖÖ·½Ê½°ÑÕâЩÀàÐÍ´«¸ø OC ²ÅÄÜÍê³ÉÐÂÔö·½·¨£¬±È½ÏÂé·³¡£ºóÀ´Í¦¶àÈ˱ȽϹØ×¢Õâ¸öÎÊÌ⣬²»ÄÜÐÂÔö·½·¨µ¼ÖÂ
action-target ģʽÎÞ·¨Óã¬ÎÒÒ²¿ªÊ¼ÏëÓÐûÓиüºÃµÄ·½·¨ÊµÏÖÌí¼Ó·½·¨¡£ºóÀ´µÄ½â¾ö·½°¸ÊÇËùÓÐÀàÐͶ¼ÓÃ
id ±íʾ£¬ÒòΪ·´ÕýÐÂÔöµÄ·½·¨¶¼ÊÇ JS ÔÚÓÃ(Protocol¶¨ÒåµÄ·½·¨³ýÍâ)£¬²»ÈçÐÂÔöµÄ·½·¨·µ»ØÖµºÍ²ÎÊýȫͳһ³É
id ÀàÐÍ£¬ÕâÑù¾Í²»Óô«ÀàÐÍÁË¡£
ÏÖÔÚ defineClass ¶¨ÒåµÄ·½·¨»á¾¹ý JS °ü×°£¬±ä³ÉÒ»¸ö°üº¬²ÎÊý¸öÊýºÍ·½·¨ÊµÌåµÄÊý×é´«¸øOC£¬OC»áÅжÏÈç¹û·½·¨ÒÑ´æÔÚ£¬¾ÍÖ´ÐÐÌæ»»µÄ²Ù×÷£¬Èô²»´æÔÚ£¬¾Íµ÷ÓÃ
class_addMethod() ÐÂÔöÒ»¸ö·½·¨£¬Í¨¹ý´«¹ýÀ´µÄ²ÎÊý¸öÊýºÍ·½·¨ÊµÌåÉú³ÉÐ嵀 Method£¬°Ñ
Method µÄ²ÎÊýºÍ·µ»ØÖµÀàÐͶ¼ÉèΪid¡£ÕâÀï JS µ÷ÓÃÐÂÔö·½·¨×ßµÄÁ÷³Ì»¹ÊÇ forwardInvocation
ÕâÒ»Ìס£
ii. Protocol
¶ÔÓÚÐÂÔöµÄ·½·¨»¹ÓиöÎÊÌ⣬Èôij¸öÀàʵÏÖÁËij protocol£¬protocol·½·¨ÀïÓпÉÑ¡µÄ·½·¨£¬ËüµÄ²ÎÊý²»È«ÊÇ
id ÀàÐÍ£¬ÀýÈç UITableViewDataSource µÄÒ»¸ö·½·¨£º
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index; |
ÈôÔÀàûÓÐʵÏÖÕâ¸ö·½·¨£¬ÔÚ JS ÀïʵÏÖÁË£¬»á×ßµ½ÐÂÔö·½·¨µÄÂß¼£¬Ã¿¸ö²ÎÊýÀàÐͶ¼±ä³É id£¬ÓëÕâ¸ö protocol
·½·¨²»Æ¥Å䣬²úÉú´íÎó¡£
ÕâÀï¾ÍÐèÒªÔÚ JS ¶¨ÒåÀàʱ¸ø³öʵÏÖµÄ protocol£¬ÕâÑùÔÚÐÂÔö Protocol ÀïÒѶ¨ÒåµÄ·½·¨Ê±£¬²ÎÊýÀàÐͻᰴÕÕ
Protocol ÀïµÄ¶¨ÒåȥʵÏÖ£¬Protocol µÄ¶¨Ò巽ʽ¸ú OC ÉϵÄд·¨Ò»Ö£º
defineClass("JPViewController: UIViewController <UIAlertViewDelegate>", { alertView_clickedButtonAtIndex: function(alertView, buttonIndex) { console.log('clicked index ' + buttonIndex) } }) |
ʵÏÖ·½Ê½±È½Ï¼òµ¥£¬Ï顄 Protocol Ãû½âÎö³öÀ´£¬µ± JS ¶¨ÒåµÄ·½·¨ÔÚÔÓÐÀàÉÏÕÒ²»µ½Ê±£¬ÔÙͨ¹ý objc_getProtocol
ºÍ protocol_copyMethodDescriptionList runtime ½Ó¿Ú°Ñ Protocol
¶ÔÓ¦µÄ·½·¨È¡³öÀ´£¬ÈôÆ¥ÅäÉÏ£¬Ôò°´Æä·½·¨µÄ¶¨Òå×ß·½·¨Ìæ»»µÄÁ÷³Ì¡£
5. PropertyʵÏÖ
ÈôÒªÔÚ JS ²Ù×÷ OC ¶ÔÏóÉÏÒѶ¨ÒåºÃµÄ property£¬Ö»ÐèÒªÏñµ÷ÓÃÆÕͨ OC ·½·¨Ò»Ñù£¬µ÷ÓÃÕâ¸ö¶ÔÏóµÄ
get/set ·½·¨¾ÍÐÐÁË£º
//OC @property (nonatomic) NSString *data; @property (nonatomic) BOOL *succ; ``` ``` //JS self.setSucc(1); var str = self.data(); |
[
ÈôÒª¶¯Ì¬¸ø OC ¶ÔÏóÐÂÔö property£¬ÔòÒªÁí±Ùõè¾¶£º
defineClass('JPTableViewController : UITableViewController', { dataSource: function() { var data = self.getProp('data') if (data) return data; data = [1,2,3] self.setProp_forKey(data, 'data') return data; } } |
JSPatch¿ÉÒÔͨ¹ý -getProp:£¬ -setProp:forKey: ÕâÁ½¸ö·½·¨¸ø¶ÔÏó¶¯Ì¬Ìí¼Ó³ÉÔ±±äÁ¿¡£ÊµÏÖÉÏÓÃÁËÔËÐÐʱ¹ØÁª½Ó¿Ú
objc_getAssociatedObject() ºÍ objc_setAssociatedObject()
Ä£Ä⣬Ï൱ÓÚ°ÑÒ»¸ö¶ÔÏó¸úµ±Ç°¶ÔÏóself¹ØÁªÆðÀ´£¬ÒÔºó¿ÉÒÔͨ¹ýµ±Ç°¶ÔÏóselfÕÒµ½Õâ¸ö¶ÔÏ󣬸ú³ÉÔ±µÄЧ¹ûÒ»Ñù£¬Ö»ÊÇÒ»¶¨µÃÊÇid¶ÔÏóÀàÐÍ¡£
±¾À´OCÓÐ class_addIvar() ¿ÉÒÔΪÀàÌí¼Ó³ÉÔ±£¬µ«±ØÐëÔÚÀà×¢²á֮ǰÌí¼ÓÍ꣬ע²áÍê³ÉºóÎÞ·¨Ìí¼Ó£¬ÕâÒâζ×Å¿ÉÒÔΪÔÚJSÐÂÔöµÄÀàÌí¼Ó³ÉÔ±£¬µ«²»ÄÜΪOCÉÏÒÑ´æÔÚµÄÀàÌí¼Ó£¬ËùÒÔÖ»ÄÜÓÃÉÏÊö·½·¨Ä£Äâ¡£
6. self¹Ø¼ü×Ö
defineClass("JPViewController: UIViewController", { viewDidLoad: function() { var view = self.view() ... }, } |
JSPatchÖ§³ÖÖ±½ÓÔÚdefineClassÀïµÄʵÀý·½·¨ÀïÖ±½ÓʹÓà self ¹Ø¼ü×Ö£¬¸úOCÒ»Ñù self
ÊÇÖ¸µ±Ç°¶ÔÏó£¬Õâ¸ö self ¹Ø¼ü×ÖÊÇÔõÑùʵÏÖµÄÄØ£¿Êµ¼ÊÉÏÕâ¸öselfÊǸöÈ«¾Ö±äÁ¿£¬ÔÚ defineClass
Àï¶ÔʵÀý·½·¨ ·½·¨½øÐÐÁ˰ü×°£¬ÔÚµ÷ÓÃʵÀý·½·¨Ö®Ç°£¬»á°ÑÈ«¾Ö±äÁ¿ self ÉèΪµ±Ç°¶ÔÏ󣬵÷ÓÃÍêºóÉè»Ø¿Õ£¬¾Í¿ÉÒÔÔÚÖ´ÐÐʵÀý·½·¨µÄ¹ý³ÌÖÐʹÓÃ
self ±äÁ¿ÁË¡£ÕâÊÇÒ»¸öССµÄtrick¡£
7. super¹Ø¼ü×Ö
defineClass("JPViewController: UIViewController", { viewDidLoad: function() { self.super.viewDidLoad() }, } |
OC Àï super ÊÇÒ»¸ö¹Ø¼ü×Ö£¬ÎÞ·¨Í¨¹ý¶¯Ì¬·½·¨Äõ½ super£¬ÄÇô JSPatch µÄ super
ÊÇÔõôʵÏֵģ¿Êµ¼ÊÉϵ÷Óà super µÄ·½·¨£¬OC ×öµÄÊÂÊǵ÷Óø¸ÀàµÄij¸ö·½·¨£¬²¢°Ñµ±Ç°¶ÔÏóµ±³É self
´«È븸Àà·½·¨£¬ÎÒÃÇֻҪģÄâËüÕâ¸ö¹ý³Ì¾ÍÐÐÁË¡£
Ê×ÏÈ JS ¶ËÐèÒª¸æËßOCÏëµ÷ÓõÄÊǵ±Ç°¶ÔÏóµÄ super ·½·¨£¬×ö·¨Êǵ÷Óà self.super()ʱ£¬__c
º¯Êý»á×öÌØÊâ´¦Àí£¬·µ»ØÒ»¸öеĶÔÏó£¬Õâ¸ö¶ÔÏóͬÑù±£´æÁË OC ¶ÔÏóµÄÒýÓã¬Í¬Ê±±êʶ __isSuper
= 1¡£
... if (methodName == 'super') { return function() { return {__obj: self.__obj, __clsName: self.__clsName, __isSuper: 1} } } ... |
ÔÙÓÃÕâ¸ö·µ»ØµÄ¶ÔÏóÈ¥µ÷Ó÷½·¨Ê±£¬__c º¯Êý»á°Ñ __isSuper Õâ¸ö±êʶλ´«¸ø OC£¬¸æËß OC
Òªµ÷ super µÄ·½·¨¡£OC ×öµÄÊÂÇéÊÇ£¬Èç¹ûÊǵ÷Óà super ·½·¨£¬ÕÒµ½ superClass Õâ¸ö·½·¨µÄ
IMP ʵÏÖ£¬Îªµ±Ç°ÀàÐÂÔöÒ»¸ö·½·¨Ö¸Ïò super µÄ IMP ʵÏÖ£¬ÄÇôµ÷ÓÃÕâ¸öÀàµÄз½·¨¾ÍÏ൱ÓÚµ÷ÓÃ
super ·½·¨¡£°ÑÒªµ÷Óõķ½·¨Ìæ»»³ÉÕâ¸öз½·¨£¬¾ÍÍê³É super ·½·¨µÄµ÷ÓÃÁË¡£
static id callSelector(NSString *className, NSString *selectorName, NSArray *arguments, id instance, BOOL isSuper) { ... if (isSuper) { NSString *superSelectorName =
NSString stringWithFormat:@"SUPER_%@", selectorName]; SEL superSelector = NSSelectorFromString(superSelectorName); Class superCls = [cls superclass]; Method superMethod = class_getInstanceMethod(superCls, selector); IMP superIMP = method_getImplementation(superMethod); class_addMethod(cls, superSelector, superIMP, method_getTypeEncoding(superMethod)); selector = superSelector; } ... } |
À©Õ¹
1. Struct Ö§³Ö
struct ÀàÐÍÔÚ JS Óë OC ¼ä´«µÝÐèÒª×öת»»´¦Àí£¬Ò»¿ªÊ¼ JSPatch Ö»´¦ÀíÁËÔÉúµÄ NSRange
/ CGRect / CGSize / CGPoint ÕâËĸö£¬ÆäËû struct ÀàÐÍÎÞ·¨ÔÚ OC /
JS ¼ä´«µÝ¡£¶ÔÓÚÆäËûÀàÐ굀 struct Ö§³Ö£¬ÎÒÊDzÉÓÃÀ©Õ¹µÄ·½Ê½£¬ÈÃдÀ©Õ¹µÄÈËÊÖ¶¯´¦Àíÿ¸öÒªÖ§³ÖµÄ
struct ½øÐÐÀàÐÍת»»£¬ÕâÖÖ×ö·¨Ã»ÎÊÌ⣬µ«ÐèÒªÔÚ OC ´úÂëдºÃÕâЩÀ©Õ¹£¬ÎÞ·¨¶¯Ì¬Ìí¼Ó£¬×ª»»µÄʵÏÖÒ²±È½Ï·±Ëö¡£ÓÚÊÇתΪÁíÒ»ÖÖʵÏÖ£º
/* struct JPDemoStruct { CGFloat a; long b; double c; BOOL d; } */ require('JPEngine').defineStruct({ "name": "JPDemoStruct", "types": "FldB", "keys": ["a", "b", "c", "d"] }) |
¿ÉÒÔÔÚ JS ¶¯Ì¬¶¨ÒåÒ»¸öÐ嵀 struct£¬Ö»ÐèÌṩ struct Ãû£¬Ã¿¸ö×ֶεÄÀàÐÍÒÔ¼°Ã¿¸ö×ֶζÔÓ¦µÄÔÚ
JS µÄ¼üÖµ£¬¾Í¿ÉÒÔÖ§³ÖÕâ¸ö struct ÀàÐÍÔÚ JS ºÍ OC ¼ä´«µÝÁË£º
//OC @implementation JPObject + (void)passStruct:(JPDemoStruct)s; + (JPDemoStruct)returnStruct; @end |
//JS require('JPObject').passStruct({a:1, b:2, c:4.2, d:1}) var s = require('JPObject').returnStruct(); |
ÕâÀïµÄʵÏÖÔÀíÊÇ˳Ðòȥȡ struct Àïÿ¸ö×ֶεÄÖµ£¬ÔÙ¸ù¾Ý key ÖØÐ°ü×°³É NSDictionary
´«¸ø JS£¬ÔõÑù˳ÐòÈ¡ struct ÿ×ֶεÄֵĨ£¿¿ÉÒÔ¸ù¾Ý´«½øÀ´µÄ struct ×ֶεıäÁ¿ÀàÐÍ£¬Äõ½ÀàÐͶÔÓ¦µÄ³¤¶È£¬Ë³Ðò¿½±´³ö
struct ¶ÔӦλÖúͳ¤¶ÈµÄÖµ£¬¾ßÌåʵÏÖ£º
for (int i = 0; i < types.count; i ++) { size_t size = sizeof(types[i]); //types[i] ÊÇ float double int µÈÀàÐÍ void *val = malloc(size); memcpy(val, structData + position, size); position += size; } |
struct ´Ó JS µ½ OC µÄת»»Í¬Àí£¬Ö»ÊÇ·´¹ýÀ´£¬ÏÈÉú³ÉÕû¸ö struct ´óСµÄÄÚ´æµØÖ·£¨Í¨¹ý
struct ËùÓÐ×Ö¶ÎÀàÐÍ´óСÀÛ¼Ó£©£¬ÔÙÖð½¥È¡³ö JS ´«¹ýÀ´µÄÖµ½øÐÐÀàÐÍת»»¿½±´µ½Õâ¶ËÄÚ´æÀï¡£
ÕâÖÖ×ö·¨Ð§¹ûºÜºÃ£¬JS ¶ËÒªÓÃÒ»¸öÐ嵀 struct ÀàÐÍ£¬²»ÐèÒª OC ÊÂÏȶ¨ÒåºÃ£¬¿ÉÒÔÖ±½Ó¶¯Ì¬Ìí¼ÓеÄ
struct ÀàÐÍÖ§³Ö£¬µ«ÕâÖÖ·½·¨ÒÀÀµ struct ¸÷¸ö×Ö¶ÎÔÚÄÚ´æ¿Õ¼äÉϵÄÑϸñÅÅÁУ¬Èç¹ûijЩ»úÆ÷ÔڵײãʵÏÖÉ϶Ô
struct µÄ×ֶνøÐÐһЩ×Ö½Ú¶ÔÆëÖ®ÀàµÄ´¦Àí£¬ÕâÖÖ·½Ê½Ã»·¨ÓÃÁË£¬²»¹ýĿǰÔÚ iOS ÉÏ»¹Ã»Åöµ½ÕâÑùµÄÎÊÌâ¡£
2. C º¯ÊýÖ§³Ö
C º¯Êýû·¨Í¨¹ý·´ÉäÈ¥µ÷Óã¬ËùÒÔÖ»ÄÜͨ¹ýÊÖ¶¯×ª½ÓµÄ·½Ê½Èà JS µ÷ C ·½·¨£¬¾ßÌå¾ÍÊÇͨ¹ý JavaScriptCore
µÄ·½·¨ÔÚ JS µ±Ç°×÷ÓÃÓòÉ϶¨ÒåÒ»¸ö C º¯ÊýͬÃû·½·¨£¬ÔÚÕâ¸ö·½·¨ÊµÏÖÀïµ÷Óà C º¯Êý£¬ÒÔÖ§³Ö memcpy()
ΪÀý£º
context[@"memcpy"] = ^(JSValue *des, JSValue *src, size_t n) { memcpy(des, src, n); }; |
ÕâÑù¾Í¿ÉÒÔÔÚ JS µ÷Óà memcpy() º¯ÊýÁË¡£Êµ¼ÊÉÏÕâÀﻹÓвÎÊý JS <-> OC
ת»»ÎÊÌ⣬ÕâÀïÏȺöÂÔ¡£
ÕâÀïÓÐÁ½¸öÎÊÌ⣺
a.Èç¹ûÕâЩ C º¯ÊýµÄÖ§³Ö¶¼Ð´ÔÚ JSPatch Ô´ÎļþÀԴÎļþ»á·Ç³£ÅÓ´ó¡£
b.Èç¹ûÒ»¿ªÊ¼¾Í¸ø JS ¼ÓÕâЩº¯Êý¶¨Ò壬ÈôÒªÖ§³ÖµÄ C º¯ÊýÁ¿´óʱ»áÓ°ÏìÐÔÄÜ¡£
¶Ô´ËÉè¼ÆÁËÒ»ÖÖÀ©Õ¹µÄ·½Ê½È¥½â¾öÕâÁ½¸öÎÊÌ⣬JSPatch ÐèÒª×öµÄ¾ÍÊÇΪÍⲿÌṩ JS ÔËÐÐÉÏÏÂÎÄ JSContext£¬ÒÔ¼°²ÎÊýת»»µÄ·½·¨£¬×îÖÕÉè¼Æ³öÀ´µÄÀ©Õ¹½Ó¿ÚÊÇÕâÑù£º
@interface JPExtension : NSObject + (void)main:(JSContext *)context; + (void *)formatPointerJSToOC:(JSValue *)val; + (id)formatPointerOCToJS:(void *)pointer; + (id)formatJSToOC:(JSValue *)val; + (id)formatOCToJS:(id)obj; @end |
s
+main ·½·¨±©Â¶ÁË JSPatch µÄÔËÐл·¾³ JSContext ¸øÍⲿ£¬¿ÉÒÔ×ÔÓÉÔÚÕâ¸ö JSContext
ÉϼӺ¯Êý¡£ÁíÍâËĸö formatXXX ·½·¨¶¼ÊDzÎÊýת»»·½·¨¡£ÉÏÊöµÄ memcpy() ÍêÕûµÄÀ©Õ¹¶¨ÒåÈçÏ£º
@implementation JPMemory + (void)main:(JSContext *)context { context[@"memcpy"] = ^id(JSValue *des, JSValue *src, size_t n) { void *ret = memcpy([self formatPointerJSToOC:des], [self formatPointerJSToOC:src], n); return [self formatPointerOCToJS:ret]; }; } @end |
ͬʱ JSPatch ÌṩÁË +addExtensions: ½Ó¿Ú£¬Èà JS ¶Ë¿ÉÒÔ¶¯Ì¬¼ÓÔØÄ³¸öÀ©Õ¹£¬ÔÚÐèÒªµÄʱºòÔÙ¸ø
JS ÉÏÏÂÎÄÌí¼ÓÕâЩ C º¯Êý£º
require('JPEngine').addExtensions(['JPMemory']) |
ʵ¼ÊÉÏ»¹ÓÐÁíÒ»ÖÖ·½·¨Ìí¼Ó C º¯ÊýµÄÖ§³Ö£¬¾ÍÊǶ¨Òå OC ·½·¨×ª½Ó£º
@implementation JPCFunctions + (void)memcpy:(void *)des src:(void *)src n:(size_t)n { memcpy(des, src, n); } @end |
È»ºóÖ±½ÓÔÚ JS ÉÏÕâÑùµ÷£º
require('JPFunctions').memcpy_src_n(des, src, n); |
ÕâÑùµÄ×ö·¨²»ÐèÒªÀ©Õ¹»úÖÆ£¬Ò²²»ÐèÒªÔÚʵÏÖʱ½øÐвÎÊýת»»£¬µ«ÒòΪËü×ßµÄÊÇ OC runtime ÄÇÒ»Ì×£¬Ïà±ÈÀ©Õ¹Ö±½Óµ÷Óõķ½Ê½£¬ËÙ¶ÈÂýÁËÒ»±¶£¬ÎªÁ˸üºÃµÄÐÔÄÜ£¬»¹ÊÇÌṩһÌ×À©Õ¹½Ó¿Ú¡£
ϸ½Ú
Õû¸ö JSPatch µÄ»ù´¡ÔÀíÉÏÃæ´óÖ²ûÊöÍêÁË£¬½ÓÏÂÀ´ÔÚ¿´¿´Ò»Ð©ÊµÏÖÉÏÅöµ½µÄ¿ÓºÍµÄϸ½ÚÎÊÌâ¡£
1. Special Struct
ÉÏÎÄÌáµ½»á°ÑÒª¸²¸ÇµÄ·½·¨Ö¸Ïò_objc_msgForward£¬½øÐÐת·¢²Ù×÷£¬ÕâÀï³öÏÖÒ»¸öÎÊÌ⣬Èç¹ûÌæ»»·½·¨µÄ·µ»ØÖµÊÇijЩ
struct£¬Ê¹Óà _objc_msgForward£¨»òÕß֮ǰµÄ @selector(__JPNONImplementSelector)£©»á
crash¡£¼¸¾Õ·×ª£¬ÕÒµ½Á˽â¾ö·½·¨£º¶ÔÓÚijЩ¼Ü¹¹Ä³Ð© struct£¬±ØÐëʹÓà _objc_msgForward_stret
´úÌæ _objc_msgForward¡£ÎªÊ²Ã´ÒªÓà _objc_msgForward_stret ÄØ£¬ÕÒµ½Ò»ÆªËµÃ÷
objc_msgSend_stret ºÍ objc_msgSend Çø±ðµÄÎÄÕ£ºhttp://sealiesoftware.com/blog/archive/2008/10/30/objcexplainobjcmsgSendstret.html£©£¬ËµµÃ±È½ÏÇå³þ£¬ÔÀíÊÇÒ»ÑùµÄ£¬ÊÇCµÄһЩµ×²ã»úÖÆµÄÔÒò£¬¼òµ¥¸´Êöһϣº
´ó¶àÊý CPU ÔÚÖ´ÐÐ C º¯Êýʱ»á°Ñǰ¼¸¸ö²ÎÊý·Å½ø¼Ä´æÆ÷À¶Ô obj_msgSend À´ËµÇ°Á½¸ö²ÎÊý¹Ì¶¨ÊÇ
self / _cmd£¬ËüÃÇ»á·ÅÔڼĴæÆ÷ÉÏ£¬ÔÚ×îºóÖ´ÐÐÍêºó·µ»ØÖµÒ²»á±£´æÔڼĴæÆ÷ÉÏ£¬È¡Õâ¸ö¼Ä´æÆ÷µÄÖµ¾ÍÊÇ·µ»ØÖµ£º
-(int) method:(id)arg; r3 = self r4 = _cmd, @selector(method:) r5 = arg (on exit) r3 = returned int |
ÆÕͨµÄ·µ»ØÖµ(int/pointer)ºÜС£¬·ÅÔڼĴæÆ÷ÉÏûÎÊÌ⣬µ«ÓÐЩ struct ÊǺܴóµÄ£¬¼Ä´æÆ÷·Å²»Ï£¬ËùÒÔÒªÓÃÁíÒ»ÖÖ·½Ê½£¬ÔÚÒ»¿ªÊ¼ÉêÇëÒ»¶ÎÄڴ棬°ÑÖ¸Õë±£´æÔڼĴæÆ÷ÉÏ£¬·µ»ØÖµÍùÕâ¸öÖ¸ÕëÖ¸ÏòµÄÄÚ´æÐ´Êý¾Ý£¬ËùÒԼĴæÆ÷ÒªÌÚ³öÒ»¸öλÖ÷ÅÕâ¸öÖ¸Õ룬self
/ _cmd ÔڼĴæÆ÷µÄλÖþͱäÁË£º
-(struct st) method:(id)arg; r3 = &struct_var (in caller's stack frame) r4 = self r5 = _cmd, @selector(method:) r6 = arg (on exit) return value written into struct_var |
²»ÖªµÀ self / _cmd µÄλÖñäÁË£¬ËùÒÔÒªÓÃÁíÒ»¸ö·½·¨ objc_msgSend_stret ´úÌæ¡£ÔÀí´ó¸Å¾ÍÊÇÕâÑù¡£
ÉÏÃæËµÄ³Ð©¼Ü¹¹Ä³Ð© struct ÓÐÎÊÌ⣬ÄǾßÌåÊÇÄÄÐ©ÄØ£¿iOS ¼Ü¹¹ÖÐ·Ç arm64 µÄ¶¼ÓÐÕâÎÊÌ⣬¶øÔõÑùµÄ
struct ÐèÒª×ßÉÏÊöÁ÷³ÌÓà xxx_stret ´úÌæÔ·½·¨ÔòûÓÐÃ÷È·µÄ¹æÔò£¬OC ҲûÓÐÌṩ½Ó¿Ú£¬Ö»ÓÐÔÚÒ»¸öÆæÝâµÄ½Ó¿ÚÉÏ͸¶ÁËÕâ¸öÌì»ú£¬ÓÚÊÇÓÐÕâÑùÒ»¸öÉñÆæµÄÅжϣº
if ([methodSignature.debugDescription rangeOfString: @"is special struct return? YES"].location != NSNotFound) |
ÔÚ NSMethodSignature µÄ debugDescription ÉÏ´ò³öÁËÊÇ·ñ special
struct£¬Ö»ÄÜͨ¹ýÕâ×Ö·û´®Åжϡ£ËùÒÔ×îÖյĴ¦ÀíÊÇ£¬ÔÚ·Ç arm64 Ï£¬ÊÇ special struct
¾Í×ß _objc_msgForward_stret£¬·ñÔò×ß _objc_msgForward¡£
2. ÄÚ´æÎÊÌâ
i. Double Release
ʵÏÖ¹ý³ÌÖÐÅöµ½Ò»Ð©ÄÚ´æÎÊÌ⣬Ê×ÏÈÊÇ Double Release ÎÊÌâ¡£´Ó -forwardInvocation:
ÀïµÄ NSInvocation ¶ÔÏóÈ¡²ÎÊýֵʱ£¬Èô²ÎÊýÖµÊÇidÀàÐÍ£¬ÎÒÃÇ»áÕâÑùÈ¡:
id arg; [invocation getArgument:&arg atIndex:i]; |
µ«ÕâÑùµÄд·¨»áµ¼Ö crash£¬ÕâÊÇÒòΪ id arg ÔÚARCÏÂÏ൱ÓÚ __strong id arg£¬ÈôÕâʱÔÚ´úÂëÏÔʽΪ
arg ¸³Öµ£¬¸ù¾Ý ARC µÄ»úÖÆ£¬»á×Ô¶¯²åÈëÒ»Ìõ retain Óï¾ä£¬È»ºóÔÚÍ˳ö×÷ÓÃÓòʱ²åÈë release
Óï¾ä£º
- (void)method { id arg = [SomeClass getSomething]; // [arg retain] ... // [arg release] Í˳ö×÷ÓÃÓòǰrelease } |
µ«ÎÒÃÇÕâÀï²»ÊÇÏÔʽ¶Ô arg ½øÐи³Öµ£¬¶øÊÇ´«Èë -getArgument:atIndex: ·½·¨£¬ÔÚÕâÀïÃæ¸³Öµºó
ARC ûÓÐ×Ô¶¯¸øÕâ¸ö±äÁ¿²åÈë retain Óï¾ä£¬µ«Í˳ö×÷ÓÃÓòʱ»¹ÊÇ×Ô¶¯²åÈëÁË release Óï¾ä£¬µ¼ÖÂÕâ¸ö±äÁ¿¶àÊÍ·ÅÁËÒ»´Î£¬µ¼ÖÂ
crash¡£½â¾ö·½·¨ÊÇ°Ñ arg ±äÁ¿Éè³É _unsafeunretained »ò __weak£¬Èà ARC
²»ÔÚËüÍ˳ö×÷ÓÃÓòʱ²åÈë release Óï¾ä¼´¿É£º
__unsafe_unretained id arg; [invocation getReturnValue:&arg]; |
»¹¿ÉÒÔͨ¹ý __bridge ת»»Èþֲ¿±äÁ¿³ÖÓзµ»Ø¶ÔÏó£¬ÕâÑù×öÒ²ÊÇûÎÊÌâµÄ£º
id returnValue; void *result; [invocation getReturnValue:&result]; returnValue = (__bridge id)result; |
ii. ÄÚ´æÐ¹Â¶
Double Release µÄÎÊÌâ½â¾öÁË£¬ÓÖÅöµ½ÄÚ´æÐ¹Â¶µÄ¿Ó¡£Ä³Ìì github issue ÉÏÓÐÈËÌá¶ÔÏóÉú³ÉºóûÓÐÊÍ·Å£¬¼¸¾ÅŲ飬¶¨Î»µ½»¹ÊÇÕâÀï
NSInvocation getReturnValue µÄÎÊÌ⣬µ± NSInvocation µ÷ÓõÄÊÇ
alloc ʱ£¬·µ»ØµÄ¶ÔÏó²¢²»»áÊÍ·Å£¬Ôì³ÉÄÚ´æÐ¹Â¶£¬Ö»Óаѷµ»Ø¶ÔÏóµÄÄÚ´æ¹ÜÀíÈ¨ÒÆ½»³öÀ´£¬ÈÃÍⲿ¶ÔÏó°ïËüÊͷŲÅÐУº
id returnValue; void *result; [invocation getReturnValue:&result]; if ([selectorName isEqualToString:@"alloc"] || [selectorName isEqualToString:@"new"]) { returnValue = (__bridge_transfer id)result; } else { returnValue = (__bridge id)result; } |
ÕâÊÇÒòΪ ARC ¶Ô·½·¨ÃûÓÐÔ¼¶¨£¬µ±·½·¨Ãû¿ªÍ·ÊÇ alloc / new / copy / mutableCopy
ʱ£¬·µ»ØµÄ¶ÔÏóÊÇ retainCount = 1 µÄ£¬³ý´ËÖ®Í⣬·½·¨·µ»ØµÄ¶ÔÏó¶¼ÊÇ autorelease
µÄ£¬°´ÉÏÒ»½ÚµÄ˵·¨£¬¶ÔÓÚÆÕͨ·½·¨·µ»ØÖµ£¬ARC »áÔÚ¸³¸ø strong ±äÁ¿Ê±×Ô¶¯²åÈë retain Óï¾ä£¬µ«¶ÔÓÚ
alloc µÈÕâЩ·½·¨£¬²»»áÔÙ×Ô¶¯²åÈë retain Óï¾ä£º
id obj = [SomeObject alloc]; //alloc ·½·¨·µ»ØµÄ¶ÔÏó retainCount ÒÑ +1£¬ÕâÀï²»ÐèÒªretain id obj2 = [SomeObj someMethod]; //·½·¨·µ»ØµÄ¶ÔÏóÊÇ autorelease£¬ARC »áÔÙÕâÀï×Ô¶¯²åÈë [obj2 retain] Óï¾ä |
¶ø ARC ²¢Ã»Óд¦Àí·ÇÏÔʾµ÷ÓÃʱµÄÇé¿ö£¬ÕâÀﶯ̬µ÷ÓÃÕâЩ·½·¨Ê±£¬ARC ¶¼²»»á×Ô¶¯²åÈë retain£¬ÕâÖÖÇé¿öÏ£¬alloc
/ new µÈÕâÀà·½·¨·µ»ØÖµµÄ retainCount ÊÇ»á±ÈÆäËû·½·¨·µ»ØÖµ¶à1µÄ£¬ËùÒÔÐèÒªÌØÊâ´¦ÀíÕâÀà·½·¨¡£
3. ¡®_¡¯µÄ´¦Àí
JSPatch ÓÃÏ»®Ïß¡¯¡¯Á¬½ÓOC·½·¨¶à¸ö²ÎÊý¼äµÄ¼ä¸ô£º
- (void)setObject:(id)anObject forKey:(id)aKey; <==> setObject_forKey() |
setObject_forKey()
ÄÇÈç¹ûOC·½·¨ÃûÀﺬÓÐ'_'£¬ÄǾͳöÏÖÆçÒåÁË£º
<code>- (void)set_object:(id)anObject forKey:(id)aKey; <==> set_object_forKey()</code>! |
û·¨ÖªµÀ set_object_forKey ¶ÔÓ¦µÄ selector ÊÇ set_object:forKey:
»¹ÊÇ set:object:forKey:¡£
¶Ô´ËÐèÒª¶¨¸ö¹æÔò£¬ÔÚ JS ÓÃÆäËû×Ö·û´úÌæ OC ·½·¨ÃûÀïµÄ _¡£JS ÃüÃû¹æÔò³ýÁË×ÖĸºÍÊý×Ö£¬¾ÍÖ»ÓÐ
$ ºÍ _£¬¿´ÆðÀ´Ö»ÄÜÓà $ ´úÌæÁË£¬µ«Ð§¹ûºÜ³ó£º
- (void)set_object:(id)anObject forKey:(id)aKey; - (void)_privateMethod(); <==> set$object_forKey() $privateMethod() |
ÓÚÊdz¢ÊÔÁíÒ»ÖÖ·½·¨£¬ÓÃÁ½¸öÏ»®Ïß __ ´úÌæ£º
set__object_forKey() __privateMethod() |
µ«ÓÃÁ½¸öÏ»®Ïß´úÌæÓиöÎÊÌ⣬OC ·½·¨Ãû²ÎÊýºóÃæ¼ÓÏ»®Ïß»áÆ¥Åä²»µ½
- (void)setObject_:(id)anObject forKey:(id)aKey; <==> setObject___forKey() |
ʵ¼ÊÉÏ setObject___forKey() Æ¥Åäµ½¶ÔÓ¦µÄ selector ÊÇ setObject:_forKey:¡£ËäÈ»ÓÐÕâ¸ö¿Ó£¬µ«ÒòΪºÜÉÙ¼ûµ½ÕâÖÖÆæÝâµÄÃüÃû·½Ê½£¬¸Ð¾õÎÊÌâ²»´ó£¬Ê¹ÓÃ$Ò²»áµ¼ÖÂÌæ»»²»ÁË
OC ·½·¨Ãû°üº¬ $ ×Ö·ûµÄ£¬×îÖÕΪÁË´úÂëÑÕÖµ£¬Ê¹ÓÃÁË˫ϻ®Ïß __ ±íʾ¡£
4.JPBoxing
ÔÚʹÓà JSPatch ¹ý³ÌÖз¢ÏÖJSÎÞ·¨µ÷Óà NSMutableArray / NSMutableDictionary
/ NSMutableString µÄ·½·¨È¥ÐÞ¸ÄÕâЩ¶ÔÏóµÄÊý¾Ý£¬ÒòΪÕâÈýÕß¶¼ÔÚ´Ó OC ·µ»Øµ½ JS ʱ
JavaScriptCore °ÑËüÃÇת³ÉÁË JS µÄ Array / Object / String£¬ÔÚ·µ»ØµÄʱºò¾ÍÍÑÀëÁ˸úÔ¶ÔÏóµÄÁªÏµ£¬Õâ¸öת»»ÔÚ
JavaScriptCore ÀïÊÇÇ¿ÖÆ½øÐеģ¬ÎÞ·¨Ñ¡Ôñ¡£
ÈôÏëÒªÔÚ¶ÔÏó·µ»Ø JS ºó£¬»Øµ½ OC »¹Äܵ÷ÓÃÕâ¸ö¶ÔÏóµÄ·½·¨£¬¾ÍÒª×èÖ¹ JavaScriptCore
µÄת»»£¬Î¨Ò»µÄ·½·¨¾ÍÊDz»Ö±½Ó·µ»ØÕâ¸ö¶ÔÏ󣬶øÊǶÔÕâ¸ö¶ÔÏó½øÐзâ×°£¬JPBoxing ¾ÍÊÇ×öÕâ¸öÊÂÇéµÄ£º
@interface JPBoxing : NSObject @property (nonatomic) id obj; @end @implementation JPBoxing + (instancetype)boxObj:(id)obj { JPBoxing *boxing = [[JPBoxing alloc] init]; boxing.obj = obj; return boxing; } |
°Ñ NSMutableArray / NSMutableDictionary / NSMutableString
¶ÔÏó×÷Ϊ JPBoxing µÄ³ÉÔ±±£´æÔÚ JPBoxing ʵÀý¶ÔÏóÉÏ·µ»Ø¸ø JS£¬JS Äõ½µÄÊÇ JPBoxing
¶ÔÏóµÄÖ¸Õ룬ÔÙ´«»Ø¸ø OC ʱ¾Í¿ÉÒÔͨ¹ý¶ÔÏó³ÉԱȡµ½ÔÀ´µÄ NSMutableArray / NSMutableDictionary
/ NSMutableString ¶ÔÏó£¬ÀàËÆÓÚ×°Ïä/²ðÏä²Ù×÷£¬ÕâÑù¾Í±ÜÃâÁËÕâЩ¶ÔÏó±» JavaScriptCore
ת»»¡£
ʵ¼ÊÉÏÖ»ÓпɱäµÄ NSMutableArray / NSMutableDictionary / NSMutableString
ÕâÈý¸öÀàÓбØÒªµ÷ÓÃËüµÄ·½·¨È¥Ð޸ĶÔÏóÀïµÄÊý¾Ý£¬²»¿É±äµÄ NSArray / NSDictionary /
NSString ÊÇû±ØÒªÕâÑù×öµÄ£¬Ö±½ÓתΪ JS ¶ÔÓ¦µÄÀàÐÍʹÓÃÆðÀ´»á¸ü·½±ã£¬µ«ÎªÁ˹æÔò¼òµ¥£¬JSPatch
Èà NSArray / NSDictionary / NSString ҲͬÑùÒÔ·â×°µÄ·½Ê½·µ»Ø£¬±ÜÃâÔÚµ÷ÓÃ
OC ·½·¨·µ»Ø¶ÔÏóʱ»¹ÐèÒª¹ØÐÄËü·µ»ØµÄÊǿɱ仹ÊDz»¿É±ä¶ÔÏó¡£×îºóÕû¸ö¹æÔò»¹ÊÇͦÇåÎú£ºNSArray /
NSDictionary / NSString ¼°Æä×ÓÀàÓëÆäËû NSObject ¶ÔÏóµÄÐÐΪһÑù£¬ÔÚ JS
ÉÏÄõ½µÄ¶¼Ö»ÊÇÆä¶ÔÏóÖ¸Õ룬¿ÉÒÔµ÷ÓÃËüÃÇµÄ OC ·½·¨£¬ÈôÒª°ÑÕâÈýÖÖ¶ÔÏóתΪ¶ÔÓ¦µÄ JS ÀàÐÍ£¬Ê¹ÓöîÍâµÄ
.toJS() µÄ½Ó¿Úȥת»»¡£
¶ÔÓÚ²ÎÊýºÍ·µ»ØÖµÊÇCÖ¸ÕëºÍ Class ÀàÐ͵ÄÖ§³ÖͬÑùÊÇÓà JPBoxing ·â×°µÄ·½Ê½£¬°ÑÖ¸ÕëºÍ Class
×÷Ϊ³ÉÔ±±£´æÔÚ JPBoxing ¶ÔÏóÉÏ·µ»Ø¸ø JS£¬´«»Ø OC ʱÔÙ½â³öÀ´Äõ½ÔÀ´µÄÖ¸ÕëºÍ Class£¬ÕâÑù
JSPatch ¾ÍÖ§³ÖËùÓÐÊý¾ÝÀàÐÍ OC<->JS µÄ»¥´«ÁË¡£
5. nilµÄ´¦Àí
i. Çø·ÖNSNull/nil
¶ÔÓÚ"¿Õ"µÄ±íʾ£¬JS ÓÐ null / undefined£¬OC ÓÐ nil /
NSNull£¬JavaScriptCore ¶ÔÕâЩ²ÎÊý´«µÝ´¦ÀíÊÇÕâÑùµÄ£º
´Ó JS µ½ OC£¬Ö±½Ó´«µÝ null / undefined µ½ OC ¶¼»áתΪ nil£¬Èô´«µÝ°üº¬
null / undefined µÄ Array ¸ø OC£¬»áתΪ NSNull¡£
´Ó OC µ½ JS£¬nil »áתΪ null£¬NSNull ÓëÆÕͨ NSObject Ò»Ñù·µ»ØÖ¸Õë¡£
JSPatch µÄÁ÷³ÌÉ϶¼ÊÇͨ¹ýÊý×éµÄ·½Ê½°Ñ²ÎÊý´Ó JS ´«Èë OC£¬ÕâÑùËùÓÐµÄ null / undefined
µ½ OC ¾Í¶¼±ä³ÉÁË NSNull£¬¶øÕæÕýµÄ NSNull ¶ÔÏó´«½øÀ´Ò²ÊÇ NSNull£¬ÎÞ·¨·Ö±æ´Ó JS
¹ýÀ´Êµ¼Ê´«µÄÊÇʲô£¬ÐèÒªÓÐÖÖ·½Ê½Çø·ÖÕâÁ½Õß¡£
¿¼ÂǹýÔÚ JS ÓÃÒ»¸öÌØÊâµÄ¶ÔÏó´ú±í nil£¬null / undefined Ö»ÓÃÀ´±íʾ NSNull£¬ºóÀ´¾õµÃ
NSNull ÊǺÜÉÙÊÖ¶¯´«µÝµÄ±äÁ¿£¬¶ø null / undefined ÒÔ¼° OC µÄ nil È´ºÜ³£¼û£¬ÕâÑù×ö»á¸øÈÕ³£¿ª·¢´øÀ´ºÜ´ó²»±ã¡£ÓÚÊÇ·´¹ýÀ´£¬ÔÚ
JS ÓÃÒ»¸öÌØÊâ±äÁ¿ nsnull ±íʾ NSNull£¬ÆäËû null / undefined ±íʾ nil£¬ÕâÑù´«Èë
OC ¾Í¿ÉÒÔ·Ö±æ³ö nil ºÍ NSNull£¬¾ßÌåʹÓ÷½Ê½£º
@implementation JPObject + (void)testNil:(id)obj { NSLog(@"%@", obj); } @end require("JPObject").testNil(null) //output: nil require("JPObject").testNil(nsnull) //output: NSNull |
ÕâÑù×öÓиöС¿Ó£¬¾ÍÊÇÏÔʾʹÓà NSNull.null() ×÷Ϊ²ÎÊýµ÷ÓÃʱ£¬µ½ OC ºó»á±ä³É nil£º
require("JPObject").testNil(require("NSNull").null()) //output: nil |
Õâ¸öÖ»Ðè×¢ÒâÏÂÓà nsnull ´úÌæ¾ÍÐУ¬´Ó OC ·µ»ØµÄ NSNull Ôٻش«»ØÈ¥»¹ÊÇ¿ÉÒÔʶ±ðµ½ NSNull¡£
ii.Á´Ê½µ÷ÓÃ
µÚ¶þ¸öÎÊÌ⣬nil ÔÚ JS ÀïÓà null / undefined ±íʾ£¬Ôì³ÉµÄºó¹ûÊÇÎÞ·¨Óà nil
µ÷Ó÷½·¨£¬Ò²¾ÍÎÞ·¨±£Ö¤Á´Ê½µ÷Óõݲȫ£º
@implementation JPObject + (void)returnNil { return nil; }
@end [[JPObject returnNil] hash] //it¡¯s
OK require("JPObject").returnNil().hash() //crash |
ÔÒòÊÇÔÚ JS Àï null / undefined ²»ÊǶÔÏó£¬ÎÞ·¨µ÷ÓÃÈκη½·¨£¬°üÀ¨ÎÒÃǸøËùÓжÔÏó¼ÓµÄ
__c() ·½·¨¡£½â¾ö·½Ê½Ò»¶È¾õµÃÖ»Óлص½ÉÏÃæËµµÄ£¬ÓÃÒ»¸öÌØÊâµÄ¶ÔÏó±íʾ nil£¬²ÅÄܽâ¾öÕâ¸öÎÊÌâÁË¡£µ«Ê¹ÓÃÌØÊâµÄ¶ÔÏó±íʾ
nil£¬ºó¹û¾ÍÊÇÔÚ js ÅжÏÊÇ·ñΪ nil ʱ¾ÍÒªºÜ†ªà£º
//¼ÙÉèÓÃÒ»¸ö_nil¶ÔÏó±äÁ¿±íʾOC·µ»ØµÄnil var obj = require("JPObject").returnNil() obj.hash() //¾¹ýÌØÊâ´¦ÀíûÎÊÌâ if (!obj || obj == _nil) { //Åж϶ÔÏóÊÇ·ñΪnil¾ÍµÃ¸½¼ÓÅжÏÊÇ·ñµÈÓÚ_nil } |
ÕâÑùµÄʹÓ÷½Ê½ÄÑÒÔ½ÓÊÜ£¬¼ÌÐøÑ°ÕÒ½â¾ö·½°¸£¬·¢ÏÖ true / false ÔÚ JS ÊǸö¶ÔÏó£¬ÊÇ¿ÉÒÔµ÷Ó÷½·¨µÄ£¬Èç¹ûÓÃ
false ±íʾ nil£¬¼´¿ÉÒÔ×öµ½µ÷Ó÷½·¨£¬ÓÖ¿ÉÒÔÖ±½Óͨ¹ý if (!obj) ÅжÏÊÇ·ñΪ nil£¬ÓÚÊÇÑØ×ÅÕâ¸ö·½Ïò£¬½â¾öÁËÓÃ
false ±íʾ nil ´øÀ´µÄ¸÷ÖÖ¿Ó£¬¼¸ºõÍêÃÀµØ½â¾öÁËÕâ¸öÎÊÌ⡣ʵÏÖÉϵÄϸ½Ú¾Í²»¶à˵ÁË£¬Ëµ"¼¸ºõÍêÃÀ"£¬ÊÇÒòΪ»¹ÓÐÒ»¸öС¿Ó£¬´«µÝ
false ¸ø OC ÉϲÎÊýÀàÐÍÊÇ NSNumber* µÄ·½·¨£¬OC »áµÃµ½ nil ¶ø²»ÊÇ NSNumber
¶ÔÏó£º
@implementation JPObject + (void)passNSNumber:(NSNumber *)num { NSLog(@"%@", num); } @end require("JPObject").passNSNumber(false) //output: nil |
Èç¹û OC ·½·¨µÄ²ÎÊýÀàÐÍÊÇ BOOL£¬»òÕß´«ÈëµÄÊÇ true / 0£¬¶¼ÊÇûÎÊÌâµÄ£¬ÕâС¿ÓÎÞÉË´óÑÅ¡£
ÌâÍâ»°£¬ÉñÆæµÄ JS Àï false µÄ this ¾¹È»²»ÔÙÊÇÔÀ´µÄ false£¬¶øÊÇÁíÒ»¸ö Boolean
¶ÔÏó£¬Ì«ÌØÊâÁË£º
Object.prototype.c = function(){console.log(this === false)}; false.c() //output false |
×ܽá
JSPatchµÄÔÀíÒÔ¼°Ò»Ð©ÊµÏÖϸ½Ú¾Í²ûÊöµ½ÕâÀϣÍûÕâÆªÎÄÕ¶Դó¼ÒÁ˽âºÍʹÓà JSPatch ÓаïÖú¡£
|