/*
* $Id: STRuntime.m 198 2010-01-06 23:05:30Z stuart $
*
* SafariTabs
* http://stuconnolly.com/projects/safaritabs/
*
* Copyright (c) 2010 Stuart Connolly. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#import "STRuntime.h"
#import <objc/objc-runtime.h>
/*!
* Prints all of the methods of the supplied class to the console. This method should only be used for debugging
* purposes.
*/
void STListMethodsInClass(Class class)
{
unsigned int methodCount, i;
Method *methods = class_copyMethodList(class, &methodCount);
for (i = 0; i < methodCount; i++)
{
NSLog(@"Method = %@", NSStringFromSelector(method_getName(methods[i])));
}
}
/*!
* Adds all of methods from one class to another class.
*
* @param toClass The class the methods should be added to.
* @param fromClass The class the methods should be taken from.
*/
BOOL STAddMethodsToClassFromClass(Class toClass, Class fromClass)
{
BOOL addSuccess = YES;
unsigned int methodCount, i;
Method *methods = class_copyMethodList(fromClass, &methodCount);
for (i = 0; i < methodCount; i++)
{
addSuccess = class_addMethod(toClass, method_getName(methods[i]), method_getImplementation(methods[i]), method_getTypeEncoding(methods[i]));
if (!addSuccess) break;
}
return addSuccess;
}
/*!
* Adds a method from a class to another class.
*
* @param toClass The class the method should be added to.
* @param fromClass The class the method should be taken from.
* @param selector The selector (SEL) of the method that is to be added.
* @param isInstanceMethod Indicates whether or not the method is an instance method (as opposed to a class method).
*/
BOOL STAddMethodToClass(Class toClass, Class fromClass, SEL selector, BOOL isInstanceMethod)
{
Method method = (isInstanceMethod) ? class_getInstanceMethod(fromClass, selector) : class_getClassMethod(fromClass, selector);
return class_addMethod(toClass, selector, class_getMethodImplementation(fromClass, selector), method_getTypeEncoding(method));
}
/*!
* Renames and replaces a method's name and implementation within a class, while preserving access to the
* old implementation via a different selector.
*
* @param oldClass The class the method that is to be renamed and replaced currently belongs to.
* @param newClass The class the method's new implementation currently belongs to.
* @param oldSelector The name of current selector of the method that is to be renamed and replaced.
* @param newSelector The name of the new selector
* @param newOldSelector The name of the old selector's new name under which it is to be preserved.
* @param isInstanceMethod Indicates whether or not the method is an instance method (as opposed to a class method).
*/
BOOL STRenameMethodSelector(Class oldClass, Class newClass, SEL oldSelector, SEL newSelector, SEL newOldSelector, BOOL isInstanceMethod)
{
// Get the current implementation before we replace it
IMP oldImp = class_getMethodImplementation(oldClass, oldSelector);
// Get the new method
Method newMethod = (isInstanceMethod) ? class_getInstanceMethod(newClass, newSelector) : class_getClassMethod(newClass, newSelector);
if (oldImp && newMethod) {
// Replace the current implementation with our own. Note that the method selector remains the same.
class_replaceMethod(oldClass, oldSelector, method_getImplementation(newMethod), method_getTypeEncoding(newMethod));
// Add the replaced implementation back, but with a different selector.
return class_addMethod(oldClass, newOldSelector, oldImp, method_getTypeEncoding(newMethod));
}
return NO;
}