dev.stuconnolly.com / svn / safaritabs

  1. /*
  2.  *  $Id: STRuntime.m 198 2010-01-06 23:05:30Z stuart $
  3.  *
  4.  *  SafariTabs
  5.  *  http://stuconnolly.com/projects/safaritabs/
  6.  *
  7.  *  Copyright (c) 2010 Stuart Connolly. All rights reserved.
  8.  *
  9.  *  This program is free software: you can redistribute it and/or modify
  10.  *  it under the terms of the GNU General Public License as published by
  11.  *  the Free Software Foundation, either version 3 of the License, or
  12.  *  (at your option) any later version.
  13.  *
  14.  *  This program is distributed in the hope that it will be useful,
  15.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17.  *  GNU General Public License for more details.
  18.  *
  19.  *  You should have received a copy of the GNU General Public License
  20.  *  along with this program. If not, see <http://www.gnu.org/licenses/>.
  21.  */
  22.  
  23. #import "STRuntime.h"
  24.  
  25. #import <objc/objc-runtime.h>
  26.  
  27. /*!
  28.  * Prints all of the methods of the supplied class to the console. This method should only be used for debugging
  29.  * purposes.
  30.  */
  31. void STListMethodsInClass(Class class)
  32. {
  33.     unsigned int methodCount, i;
  34.    
  35.     Method *methods = class_copyMethodList(class, &methodCount);
  36.    
  37.     for (i = 0; i < methodCount; i++)
  38.     {
  39.         NSLog(@"Method = %@", NSStringFromSelector(method_getName(methods[i])));       
  40.     }
  41. }
  42.  
  43. /*!
  44.  * Adds all of methods from one class to another class.
  45.  *
  46.  * @param toClass   The class the methods should be added to.
  47.  * @param fromClass The class the methods should be taken from.
  48.  */
  49. BOOL STAddMethodsToClassFromClass(Class toClass, Class fromClass)
  50. {
  51.     BOOL addSuccess = YES;
  52.     unsigned int methodCount, i;
  53.    
  54.     Method *methods = class_copyMethodList(fromClass, &methodCount);
  55.    
  56.     for (i = 0; i < methodCount; i++)
  57.     {
  58.         addSuccess = class_addMethod(toClass, method_getName(methods[i]), method_getImplementation(methods[i]),  method_getTypeEncoding(methods[i]));  
  59.        
  60.         if (!addSuccess) break;
  61.     }
  62.    
  63.     return addSuccess;
  64. }
  65.  
  66. /*!
  67.  * Adds a method from a class to another class.
  68.  *
  69.  * @param toClass          The class the method should be added to.
  70.  * @param fromClass        The class the method should be taken from.
  71.  * @param selector         The selector (SEL) of the method that is to be added.
  72.  * @param isInstanceMethod Indicates whether or not the method is an instance method (as opposed to a class method).
  73.  */
  74. BOOL STAddMethodToClass(Class toClass, Class fromClass, SEL selector, BOOL isInstanceMethod)
  75. {
  76.     Method method = (isInstanceMethod) ? class_getInstanceMethod(fromClass, selector) : class_getClassMethod(fromClass, selector);
  77.        
  78.     return class_addMethod(toClass, selector, class_getMethodImplementation(fromClass, selector), method_getTypeEncoding(method));
  79. }
  80.  
  81. /*!
  82.  * Renames and replaces a method's name and implementation within a class, while preserving access to the
  83.  * old implementation via a different selector.  
  84.  *
  85.  * @param oldClass         The class the method that is to be renamed and replaced currently belongs to.
  86.  * @param newClass         The class the method's new implementation currently belongs to.
  87.  * @param oldSelector      The name of current selector of the method that is to be renamed and replaced.
  88.  * @param newSelector      The name of the new selector
  89.  * @param newOldSelector   The name of the old selector's new name under which it is to be preserved.
  90.  * @param isInstanceMethod Indicates whether or not the method is an instance method (as opposed to a class method).
  91.  */
  92. BOOL STRenameMethodSelector(Class oldClass, Class newClass, SEL oldSelector, SEL newSelector, SEL newOldSelector, BOOL isInstanceMethod)
  93. {      
  94.     // Get the current implementation before we replace it
  95.     IMP oldImp = class_getMethodImplementation(oldClass, oldSelector);
  96.    
  97.     // Get the new method
  98.     Method newMethod = (isInstanceMethod) ? class_getInstanceMethod(newClass, newSelector) : class_getClassMethod(newClass, newSelector);
  99.    
  100.     if (oldImp && newMethod) {
  101.        
  102.         // Replace the current implementation with our own. Note that the method selector remains the same.
  103.         class_replaceMethod(oldClass, oldSelector, method_getImplementation(newMethod), method_getTypeEncoding(newMethod));
  104.        
  105.         // Add the replaced implementation back, but with a different selector.
  106.         return class_addMethod(oldClass, newOldSelector, oldImp, method_getTypeEncoding(newMethod));
  107.     }
  108.    
  109.     return NO;
  110. }
  111.