Replaced CPTableView+Debug by the improved version called CPTrace. Cib test: visual output for view loading perormance (avg/row since tracing start).

This commit is contained in:
cacaodev
2012-07-07 15:43:33 +02:00
parent 5017189440
commit c7ef136a7b
5 changed files with 418 additions and 208 deletions
-100
View File
@@ -1,100 +0,0 @@
@implementation CPTableView (Patcher)
+ (void)profileViewLoading
{
after.c = after.t = after.tpr = 0;
[[self class] patchMethod:@selector(_loadDataViewsInRows:columns:) beforeFunction:before afterFunction:after];
}
@end
var before = function (receiver, selector, args)
{
before.s = new Date();
};
var after = function(receiver, selector, args)
{
var d = (new Date() - before.s);
var rc = [args[0] count];
if (d > 0 && rc > 0)
{
after.t += d;
after.c ++;
after.tpr += d/rc;
}
console.log (after.c + " _loadDataViewsInRows:columns: " + rc + " rows in " + d + " ms ; avg since start / per row = " + (ROUND(100 * after.tpr/after.c) / 100) + " ms");
};
@implementation CPObject (Patcher)
+ (void)debugMethod:(SEL)aSelector
{
var before = function (receiver, selector, args)
{
CPLogConsole("BEFORE : " + receiver + " " + selector + " " + args);
};
var after = function (receiver, selector, args)
{
CPLogConsole("AFTER : " + receiver + " " + selector + " " + args);
};
[self patchMethod:aSelector beforeFunction:before afterFunction:after];
}
+ (void)patchMethod:(SEL)aSelector beforeFunction:(Function)before afterFunction:(Function)after
{
if (before == nil) before = function(){};
if (after == nil) after = function(){};
var patched_sel = CPSelectorFromString("patched_" + CPStringFromSelector(aSelector));
class_addMethod(self, patched_sel, function()
{
var orig_arguments = arguments,
receiver = orig_arguments[0],
cmd = orig_arguments[1];
var args = [];
for (var i = 2; i < orig_arguments.length; i++)
args.push(orig_arguments[i]);
orig_arguments[1] = patched_sel;
before(receiver, cmd, args);
objj_msgSend.apply(objj_msgSend, orig_arguments);
after(receiver, cmd, args);
}, "");
Swizzle(self, aSelector, patched_sel);
}
@end
function Swizzle (aClass, orig_sel, new_sel)
{
var origMethod = class_getInstanceMethod(aClass, orig_sel),
newMethod = class_getInstanceMethod(aClass, new_sel);
// This check should be in class_addMethod : Don't add and return NO and if method already exists.
var method_list = aClass.method_list,
count = method_list.length,
shouldAddMethod = YES;
while (count--)
if (method_list[count].name == orig_sel)
{
shouldAddMethod = NO;
break;
}
if (shouldAddMethod)
{
class_addMethod(aClass, orig_sel, method_getImplementation(newMethod), "");
class_replaceMethod(aClass, new_sel, method_getImplementation(origMethod), "");
}
else
method_exchangeImplementations(origMethod, newMethod);
}
@@ -7,12 +7,11 @@
*/
@import <Foundation/CPObject.j>
@import "../CPTrace.j"
var TABLE_DRAG_TYPE = @"TABLE_DRAG_TYPE",
tracing = NO;
@import "../CPTableView+Debug.j"
@implementation AppController : CPObject
{
CPWindow theWindow; //this "outlet" is connected automatically by the Cib
@@ -21,11 +20,13 @@ var TABLE_DRAG_TYPE = @"TABLE_DRAG_TYPE",
@outlet CPArrayController contentController;
CPArray content @accessors;
float avgPerRow @accessors;
}
- (void)applicationDidFinishLaunching:(CPNotification)note
{
content = [CPArray new];
avgPerRow = 0;
var path = [[CPBundle mainBundle] pathForResource:@"Data.plist"],
request = [CPURLRequest requestWithURL:path],
@@ -112,11 +113,24 @@ var TABLE_DRAG_TYPE = @"TABLE_DRAG_TYPE",
- (IBAction)trace:(id)sender
{
if (tracing)
return;
if ([sender state] == CPOnState)
{
var tlr = 0;
var f = function(a,b,c,d,e,f,g)
{
var lr = [c[0] count];
if (d > 0)
tlr += lr;
var avg = (ROUND(100 * e/tlr) / 100);
console.log(b + " " + lr + " rows in " + d + " ms ; avg/row = " + avg + " ms");
[self setAvgPerRow:avg];
}
[CPTableView profileViewLoading];
tracing = YES;
CPTrace(@"CPTableView", @"_loadDataViewsInRows:columns:", f);
}
else
CPTraceStop(@"CPTableView", @"_loadDataViewsInRows:columns:");
}
@end
File diff suppressed because one or more lines are too long
@@ -2,13 +2,13 @@
<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10">
<data>
<int key="IBDocument.SystemTarget">1070</int>
<string key="IBDocument.SystemVersion">11D50</string>
<string key="IBDocument.InterfaceBuilderVersion">2488</string>
<string key="IBDocument.AppKitVersion">1138.32</string>
<string key="IBDocument.HIToolboxVersion">568.00</string>
<string key="IBDocument.SystemVersion">11E53</string>
<string key="IBDocument.InterfaceBuilderVersion">2541</string>
<string key="IBDocument.AppKitVersion">1138.47</string>
<string key="IBDocument.HIToolboxVersion">569.00</string>
<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="NS.object.0">2488</string>
<string key="NS.object.0">2541</string>
</object>
<object class="NSArray" key="IBDocument.IntegratedClassDependencies">
<bool key="EncodedWithXMLCoder">YES</bool>
@@ -92,14 +92,16 @@
<string key="NSFrameSize">{722, 17}</string>
<reference key="NSSuperview" ref="1070384134"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="899639644"/>
<reference key="NSNextKeyView" ref="923966262"/>
<string key="NSReuseIdentifierKey">_NS:16</string>
<reference key="NSTableView" ref="270585779"/>
</object>
<object class="_NSCornerView" key="NSCornerView">
<nil key="NSNextResponder"/>
<object class="_NSCornerView" key="NSCornerView" id="923966262">
<reference key="NSNextResponder" ref="62651824"/>
<int key="NSvFlags">-2147483392</int>
<string key="NSFrame">{{224, 0}, {16, 17}}</string>
<reference key="NSSuperview" ref="62651824"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="899639644"/>
<string key="NSReuseIdentifierKey">_NS:19</string>
</object>
@@ -270,6 +272,7 @@
<reference key="NSBGColor" ref="154164329"/>
<int key="NScvFlags">4</int>
</object>
<reference ref="923966262"/>
</object>
<string key="NSFrameSize">{724, 389}</string>
<reference key="NSSuperview" ref="439893737"/>
@@ -281,71 +284,97 @@
<reference key="NSHScroller" ref="524345679"/>
<reference key="NSContentView" ref="899639644"/>
<reference key="NSHeaderClipView" ref="1070384134"/>
<reference key="NSCornerView" ref="923966262"/>
<bytes key="NSScrollAmts">QSAAAEEgAABCvAAAQrwAAA</bytes>
</object>
<object class="NSTextField" id="388559685">
<reference key="NSNextResponder" ref="439893737"/>
<int key="NSvFlags">268</int>
<string key="NSFrame">{{102, 402}, {96, 22}}</string>
<reference key="NSSuperview" ref="439893737"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="45527429"/>
<string key="NSReuseIdentifierKey">_NS:9</string>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="1067530377">
<int key="NSCellFlags">-1808793535</int>
<int key="NSCellFlags2">272630784</int>
<string key="NSContents">Editable text</string>
<reference key="NSSupport" ref="1069422166"/>
<string key="NSCellIdentifier">_NS:9</string>
<reference key="NSControlView" ref="388559685"/>
<bool key="NSDrawsBackground">YES</bool>
<object class="NSColor" key="NSBackgroundColor" id="111805313">
<int key="NSColorSpace">6</int>
<string key="NSCatalogName">System</string>
<string key="NSColorName">textBackgroundColor</string>
<object class="NSColor" key="NSColor">
<int key="NSColorSpace">3</int>
<bytes key="NSWhite">MQA</bytes>
</object>
</object>
<object class="NSColor" key="NSTextColor">
<int key="NSColorSpace">6</int>
<string key="NSCatalogName">System</string>
<string key="NSColorName">textColor</string>
<reference key="NSColor" ref="264166487"/>
</object>
</object>
</object>
<object class="NSButton" id="45527429">
<object class="NSButton" id="71984237">
<reference key="NSNextResponder" ref="439893737"/>
<int key="NSvFlags">265</int>
<string key="NSFrame">{{529, 397}, {181, 32}}</string>
<string key="NSFrame">{{528, 403}, {178, 18}}</string>
<reference key="NSSuperview" ref="439893737"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="62651824"/>
<string key="NSReuseIdentifierKey">_NS:9</string>
<bool key="NSEnabled">YES</bool>
<object class="NSButtonCell" key="NSCell" id="17559257">
<object class="NSButtonCell" key="NSCell" id="710868415">
<int key="NSCellFlags">67108864</int>
<int key="NSCellFlags2">134217728</int>
<string key="NSContents">Trace View Loading</string>
<int key="NSCellFlags2">268435456</int>
<string key="NSContents">Trace data views loading</string>
<reference key="NSSupport" ref="1069422166"/>
<string key="NSCellIdentifier">_NS:9</string>
<reference key="NSControlView" ref="45527429"/>
<int key="NSButtonFlags">-2038284288</int>
<int key="NSButtonFlags2">129</int>
<reference key="NSControlView" ref="71984237"/>
<int key="NSButtonFlags">1210863872</int>
<int key="NSButtonFlags2">2</int>
<object class="NSCustomResource" key="NSNormalImage" id="329976463">
<string key="NSClassName">NSImage</string>
<string key="NSResourceName">NSSwitch</string>
</object>
<object class="NSButtonImageSource" key="NSAlternateImage" id="152394579">
<string key="NSImageName">NSSwitch</string>
</object>
<string key="NSAlternateContents"/>
<string key="NSKeyEquivalent"/>
<int key="NSPeriodicDelay">200</int>
<int key="NSPeriodicInterval">25</int>
</object>
</object>
<object class="NSTextField" id="1007050599">
<reference key="NSNextResponder" ref="439893737"/>
<int key="NSvFlags">265</int>
<string key="NSFrame">{{330, 397}, {129, 32}}</string>
<reference key="NSSuperview" ref="439893737"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="628162211"/>
<string key="NSReuseIdentifierKey">_NS:1549</string>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="230215921">
<int key="NSCellFlags">68157504</int>
<int key="NSCellFlags2">71304192</int>
<string key="NSContents">Label</string>
<object class="NSFont" key="NSSupport">
<string key="NSName">LucidaGrande</string>
<double key="NSSize">28</double>
<int key="NSfFlags">16</int>
</object>
<string key="NSCellIdentifier">_NS:1549</string>
<reference key="NSControlView" ref="1007050599"/>
<object class="NSColor" key="NSBackgroundColor" id="614187381">
<int key="NSColorSpace">6</int>
<string key="NSCatalogName">System</string>
<string key="NSColorName">controlColor</string>
<reference key="NSColor" ref="743329450"/>
</object>
<object class="NSColor" key="NSTextColor">
<int key="NSColorSpace">2</int>
<bytes key="NSRGB">MC44Mjc0NTEwNTAzIDAuMDU4ODIzNTMzMzYgMC4wNTA5ODAzOTY1NwA</bytes>
</object>
</object>
</object>
<object class="NSTextField" id="628162211">
<reference key="NSNextResponder" ref="439893737"/>
<int key="NSvFlags">265</int>
<string key="NSFrame">{{461, 404}, {78, 17}}</string>
<reference key="NSSuperview" ref="439893737"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="71984237"/>
<string key="NSReuseIdentifierKey">_NS:1549</string>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="702549610">
<int key="NSCellFlags">68157504</int>
<int key="NSCellFlags2">272630784</int>
<string key="NSContents">ms/row</string>
<reference key="NSSupport" ref="1069422166"/>
<string key="NSCellIdentifier">_NS:1549</string>
<reference key="NSControlView" ref="628162211"/>
<reference key="NSBackgroundColor" ref="614187381"/>
<reference key="NSTextColor" ref="537790828"/>
</object>
</object>
</object>
<string key="NSFrameSize">{724, 434}</string>
<reference key="NSSuperview"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="388559685"/>
<reference key="NSNextKeyView" ref="1007050599"/>
</object>
<string key="NSScreenRect">{{0, 0}, {1680, 1028}}</string>
<string key="NSMaxSize">{10000000000000, 10000000000000}</string>
@@ -422,14 +451,6 @@
</object>
<int key="connectionID">596</int>
</object>
<object class="IBConnectionRecord">
<object class="IBActionConnection" key="connection">
<string key="label">trace:</string>
<reference key="source" ref="635946545"/>
<reference key="destination" ref="45527429"/>
</object>
<int key="connectionID">606</int>
</object>
<object class="IBConnectionRecord">
<object class="IBOutletConnection" key="connection">
<string key="label">contentController</string>
@@ -438,6 +459,14 @@
</object>
<int key="connectionID">607</int>
</object>
<object class="IBConnectionRecord">
<object class="IBActionConnection" key="connection">
<string key="label">trace:</string>
<reference key="source" ref="635946545"/>
<reference key="destination" ref="71984237"/>
</object>
<int key="connectionID">614</int>
</object>
<object class="IBConnectionRecord">
<object class="IBOutletConnection" key="connection">
<string key="label">delegate</string>
@@ -492,12 +521,7 @@
<string key="NSContents">My CELL</string>
<reference key="NSSupport" ref="1069422166"/>
<reference key="NSControlView" ref="833748488"/>
<object class="NSColor" key="NSBackgroundColor" id="614187381">
<int key="NSColorSpace">6</int>
<string key="NSCatalogName">System</string>
<string key="NSColorName">controlColor</string>
<reference key="NSColor" ref="743329450"/>
</object>
<reference key="NSBackgroundColor" ref="614187381"/>
<reference key="NSTextColor" ref="537790828"/>
</object>
</object>
@@ -522,7 +546,7 @@
<string key="NSReuseIdentifierKey">_NS:9</string>
<bool key="NSEnabled">YES</bool>
<object class="NSImageCell" key="NSCell" id="617605788">
<int key="NSCellFlags">0</int>
<int key="NSCellFlags">134217728</int>
<int key="NSCellFlags2">33554432</int>
<string key="NSCellIdentifier">_NS:9</string>
<int key="NSAlign">0</int>
@@ -549,13 +573,8 @@
<reference key="NSControlView" ref="181030507"/>
<int key="NSButtonFlags">1211912448</int>
<int key="NSButtonFlags2">2</int>
<object class="NSCustomResource" key="NSNormalImage">
<string key="NSClassName">NSImage</string>
<string key="NSResourceName">NSSwitch</string>
</object>
<object class="NSButtonImageSource" key="NSAlternateImage">
<string key="NSImageName">NSSwitch</string>
</object>
<reference key="NSNormalImage" ref="329976463"/>
<reference key="NSAlternateImage" ref="152394579"/>
<string key="NSAlternateContents"/>
<string key="NSKeyEquivalent"/>
<int key="NSPeriodicDelay">200</int>
@@ -655,7 +674,15 @@
<int key="NSCellFlags2">0</int>
<string key="NSContents">Box</string>
<reference key="NSSupport" ref="26"/>
<reference key="NSBackgroundColor" ref="111805313"/>
<object class="NSColor" key="NSBackgroundColor">
<int key="NSColorSpace">6</int>
<string key="NSCatalogName">System</string>
<string key="NSColorName">textBackgroundColor</string>
<object class="NSColor" key="NSColor">
<int key="NSColorSpace">3</int>
<bytes key="NSWhite">MQA</bytes>
</object>
</object>
<object class="NSColor" key="NSTextColor">
<int key="NSColorSpace">3</int>
<bytes key="NSWhite">MCAwLjgwMDAwMDAxMTkAA</bytes>
@@ -974,6 +1001,22 @@
</object>
<int key="connectionID">593</int>
</object>
<object class="IBConnectionRecord">
<object class="IBBindingConnection" key="connection">
<string key="label">value: avgPerRow</string>
<reference key="source" ref="1007050599"/>
<reference key="destination" ref="635946545"/>
<object class="NSNibBindingConnector" key="connector">
<reference key="NSSource" ref="1007050599"/>
<reference key="NSDestination" ref="635946545"/>
<string key="NSLabel">value: avgPerRow</string>
<string key="NSBinding">value</string>
<string key="NSKeyPath">avgPerRow</string>
<int key="NSNibBindingConnectorVersion">2</int>
</object>
</object>
<int key="connectionID">621</int>
</object>
</object>
<object class="IBMutableOrderedSet" key="objectRecords">
<object class="NSArray" key="orderedObjects">
@@ -1019,8 +1062,9 @@
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="62651824"/>
<reference ref="388559685"/>
<reference ref="45527429"/>
<reference ref="71984237"/>
<reference ref="628162211"/>
<reference ref="1007050599"/>
</object>
<reference key="parent" ref="972006081"/>
</object>
@@ -1250,20 +1294,6 @@
<reference key="object" ref="736961119"/>
<reference key="parent" ref="181030507"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">597</int>
<reference key="object" ref="388559685"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="1067530377"/>
</object>
<reference key="parent" ref="439893737"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">598</int>
<reference key="object" ref="1067530377"/>
<reference key="parent" ref="388559685"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">599</int>
<reference key="object" ref="1009603010"/>
@@ -1279,18 +1309,46 @@
<reference key="parent" ref="1009603010"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">604</int>
<reference key="object" ref="45527429"/>
<int key="objectID">612</int>
<reference key="object" ref="71984237"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="17559257"/>
<reference ref="710868415"/>
</object>
<reference key="parent" ref="439893737"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">605</int>
<reference key="object" ref="17559257"/>
<reference key="parent" ref="45527429"/>
<int key="objectID">613</int>
<reference key="object" ref="710868415"/>
<reference key="parent" ref="71984237"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">615</int>
<reference key="object" ref="1007050599"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="230215921"/>
</object>
<reference key="parent" ref="439893737"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">616</int>
<reference key="object" ref="230215921"/>
<reference key="parent" ref="1007050599"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">617</int>
<reference key="object" ref="628162211"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="702549610"/>
</object>
<reference key="parent" ref="439893737"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">618</int>
<reference key="object" ref="702549610"/>
<reference key="parent" ref="628162211"/>
</object>
</object>
</object>
@@ -1344,12 +1402,14 @@
<string>547.userInterfaceItemIdentifier</string>
<string>549.IBPluginDependency</string>
<string>550.IBPluginDependency</string>
<string>597.IBPluginDependency</string>
<string>598.IBPluginDependency</string>
<string>599.IBPluginDependency</string>
<string>600.IBPluginDependency</string>
<string>604.IBPluginDependency</string>
<string>605.IBPluginDependency</string>
<string>612.IBPluginDependency</string>
<string>613.IBPluginDependency</string>
<string>615.IBPluginDependency</string>
<string>616.IBPluginDependency</string>
<string>617.IBPluginDependency</string>
<string>618.IBPluginDependency</string>
</object>
<object class="NSArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
@@ -1413,6 +1473,8 @@
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
</object>
</object>
<object class="NSMutableDictionary" key="unlocalizedProperties">
@@ -1427,7 +1489,7 @@
<reference key="dict.values" ref="0"/>
</object>
<nil key="sourceID"/>
<int key="maxID">611</int>
<int key="maxID">621</int>
</object>
<object class="IBClassDescriber" key="IBDocument.Classes">
<object class="NSMutableArray" key="referencedPartialClassDescriptions">
+234
View File
@@ -0,0 +1,234 @@
/*
* CPTrace.j
*
* Created by cacaodev
* Copyright 2012 <cacaodev@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
var patchedClassesAndSelectors = [],
globalStack = [],
globalLevel = 0;
var Tracer = function()
{
this.td = 0;
this.tc = 0;
this.displayFunction = nil;
};
Tracer.prototype.log = function()
{
var c = globalStack.length;
for (var i = 0; i < c; i++)
{
var trace = globalStack.shift();
this.displayFunction(trace.receiver, trace.selector, trace.args, trace.duration, this.td, this.tc, trace.level);
}
};
var defaultDisplay = function(receiver, selector, args, duration, total_duration, total_count, level)
{
var message = objj_message(receiver, selector, args),
// WARNING: average duration only supported for root calls.
avg_message = (level == 0) ? (" , avg = " + (ROUND(100 * total_duration / total_count) / 100) + " ms") : "";
console.log(indent(level) + message + " in " + duration + " ms" + avg_message);
};
var indent = function(n)
{
var str = "";
while (n--)
str += " ";
return str;
};
var objj_message = function(receiver, selector, args)
{
var c = args.length,
sel = selector.split(":"),
rdesc = receiver ? [receiver description] : "<null>";
while (c--)
sel.splice(c + 1, 0, ":" + [args[c] description] + " ");
var joined = sel.join("");
if (args.length)
joined = joined.substring(0, joined.length - 1);
return ("[" + rdesc + " " + joined + "]");
};
function CPTrace(aClassName, aSelector, displayFunction)
{
var aclass = CPClassFromString(aClassName);
if (aclass)
_CPTraceClass(aclass, aSelector, displayFunction);
else if (typeof(objj_getClassList) != 'undefined')
{
var classes = [],
patchednum = 0,
numclasses = objj_getClassList(classes, 400),
regex = new RegExp(aClassName);
while (numclasses--)
{
var cls = classes[numclasses];
if (regex.test(cls))
{
console.log("Patching " + cls + " -" + aSelector);
_CPTraceClass(cls, aSelector, displayFunction);
patchednum++;
}
}
if (patchednum == 0)
console.log("Could not find any class matching '" + aClassName + "'");
else
console.log("Patched " + patchednum + " classes matching " + aClassName);
}
else
[CPException raise:CPInvalidArgumentException reason:("Unknown class name '" + aClassName + "'")];
}
var _CPTraceClass = function(aClass, aSelector, displayFunction)
{
if (![aClass instancesRespondToSelector:aSelector])
[CPException raise:CPInvalidArgumentException reason:(aClass + " does not respond to '" + aSelector + "'")];
var superclass = aClass;
while (![superclass instancesImplementsSelector:aSelector] && superclass != [CPObject class])
superclass = [superclass superclass];
var patchUniqueString = (superclass + "_" + aSelector);
if ([patchedClassesAndSelectors containsObject:patchUniqueString])
{
if (superclass == aClass)
console.log(superclass + " -" + aSelector + " is already patched. Ignoring.");
else
console.log("-" + aSelector + " is implemented in a superclass of " + aClass + " (" + superclass + ") where it's already patched. Ignoring.");
return;
}
var patched_sel = CPSelectorFromString("patched_" + CPStringFromSelector(aSelector)),
tracer = new Tracer();
tracer.displayFunction = displayFunction ? displayFunction : defaultDisplay;
class_addMethod(aClass, patched_sel, function()
{
var orig_arguments = arguments,
receiver = orig_arguments[0],
selector = orig_arguments[1],
args = [];
for (var i = 2; i < orig_arguments.length; i++)
args.push(orig_arguments[i]);
orig_arguments[1] = patched_sel;
var trace = {receiver:receiver, selector:selector, args:args, start:(new Date()), level:globalLevel};
globalStack.push(trace);
globalLevel++;
objj_msgSend.apply(objj_msgSend, orig_arguments);
var duration = (trace.duration = new Date() - trace.start);
globalLevel--;
if (globalLevel == 0)
{
if (duration > 0)
tracer.tc++;
tracer.td += trace.duration;
tracer.log();
}
}, "");
Swizzle(aClass, aSelector, patched_sel);
[patchedClassesAndSelectors addObject:patchUniqueString];
};
function CPTraceStop(aClass, aSelector)
{
var patchUniqueString = (aClass + "_" + aSelector);
if (![patchedClassesAndSelectors containsObject:patchUniqueString])
return;
var patched_sel = CPSelectorFromString("patched_" + CPStringFromSelector(aSelector));
Swizzle(CPClassFromString(aClass), patched_sel, aSelector);
[patchedClassesAndSelectors removeObject:patchUniqueString];
}
var Swizzle = function(aClass, orig_sel, new_sel)
{
var origMethod = class_getInstanceMethod(aClass, orig_sel),
newMethod = class_getInstanceMethod(aClass, new_sel);
// This check should be in class_addMethod : Don't add and return NO and if method already exists.
if (getMethodNoSuper(aClass, orig_sel) == NULL)
{
class_addMethod(aClass, orig_sel, method_getImplementation(newMethod), "");
class_replaceMethod(aClass, new_sel, method_getImplementation(origMethod), "");
}
else
method_exchangeImplementations(origMethod, newMethod);
/*
if (class_addMethod(aClass, orig_sel, method_getImplementation(newMethod), ""))
class_replaceMethod(aClass, new_sel, method_getImplementation(origMethod), "");
else
method_exchangeImplementations(origMethod, newMethod);
*/
};
var getMethodNoSuper = function(cls, sel)
{
var method_list = cls.method_list,
count = method_list.length;
while (count--)
{
var mthd = method_list[count];
if (mthd.name == sel)
return mthd;
}
return NULL;
}
@implementation CPObject (instancesImplementsSelector)
- (BOOL)instancesImplementsSelector:(SEL)aSelector
{
var methods = class_copyMethodList(self),
count = methods.length;
while (count--)
if (method_getName(methods[count]) === aSelector)
return YES;
return NO;
}
@end