/core/externals/google-toolbox-for-mac/Foundation/GTMObjC2Runtime.m
Objective C | 163 lines | 101 code | 20 blank | 42 comment | 31 complexity | 42e09ce87bcba77abba15d303e4ddd83 MD5 | raw file
1// 2// GTMObjC2Runtime.m 3// 4// Copyright 2007-2008 Google Inc. 5// 6// Licensed under the Apache License, Version 2.0 (the "License"); you may not 7// use this file except in compliance with the License. You may obtain a copy 8// of the License at 9// 10// http://www.apache.org/licenses/LICENSE-2.0 11// 12// Unless required by applicable law or agreed to in writing, software 13// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 14// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 15// License for the specific language governing permissions and limitations under 16// the License. 17// 18 19#import "GTMObjC2Runtime.h" 20 21#if GTM_MACOS_SDK && (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5) 22#import <stdlib.h> 23#import <string.h> 24 25Class object_getClass(id obj) { 26 if (!obj) return NULL; 27 return obj->isa; 28} 29 30const char *class_getName(Class cls) { 31 if (!cls) return "nil"; 32 return cls->name; 33} 34 35BOOL class_conformsToProtocol(Class cls, Protocol *protocol) { 36 // We intentionally don't check cls as it crashes on Leopard so we want 37 // to crash on Tiger as well. 38 // I logged 39 // Radar 5572978 class_conformsToProtocol crashes when arg1 is passed as nil 40 // because it seems odd that this API won't accept nil for cls considering 41 // all the other apis will accept nil args. 42 // If this does get fixed, remember to enable the unit tests. 43 if (!protocol) return NO; 44 45 struct objc_protocol_list *protos; 46 for (protos = cls->protocols; protos != NULL; protos = protos->next) { 47 for (long i = 0; i < protos->count; i++) { 48 if ([protos->list[i] conformsTo:protocol]) { 49 return YES; 50 } 51 } 52 } 53 return NO; 54} 55 56Class class_getSuperclass(Class cls) { 57 if (!cls) return NULL; 58 return cls->super_class; 59} 60 61BOOL class_respondsToSelector(Class cls, SEL sel) { 62 return class_getInstanceMethod(cls, sel) != nil; 63} 64 65Method *class_copyMethodList(Class cls, unsigned int *outCount) { 66 if (!cls) return NULL; 67 68 unsigned int count = 0; 69 void *iterator = NULL; 70 struct objc_method_list *mlist; 71 Method *methods = NULL; 72 if (outCount) *outCount = 0; 73 74 while ( (mlist = class_nextMethodList(cls, &iterator)) ) { 75 if (mlist->method_count == 0) continue; 76 methods = (Method *)realloc(methods, 77 sizeof(Method) * (count + mlist->method_count + 1)); 78 if (!methods) { 79 //Memory alloc failed, so what can we do? 80 return NULL; // COV_NF_LINE 81 } 82 for (int i = 0; i < mlist->method_count; i++) { 83 methods[i + count] = &mlist->method_list[i]; 84 } 85 count += mlist->method_count; 86 } 87 88 // List must be NULL terminated 89 if (methods) { 90 methods[count] = NULL; 91 } 92 if (outCount) *outCount = count; 93 return methods; 94} 95 96SEL method_getName(Method method) { 97 if (!method) return NULL; 98 return method->method_name; 99} 100 101IMP method_getImplementation(Method method) { 102 if (!method) return NULL; 103 return method->method_imp; 104} 105 106IMP method_setImplementation(Method method, IMP imp) { 107 // We intentionally don't test method for nil. 108 // Leopard fails here, so should we. 109 // I logged this as Radar: 110 // 5572981 method_setImplementation crashes if you pass nil for the 111 // method arg (arg 1) 112 // because it seems odd that this API won't accept nil for method considering 113 // all the other apis will accept nil args. 114 // If this does get fixed, remember to enable the unit tests. 115 // This method works differently on SnowLeopard than 116 // on Leopard. If you pass in a nil for IMP on SnowLeopard 117 // it doesn't change anything. On Leopard it will. Since 118 // attempting to change a sel to nil is probably an error 119 // we follow the SnowLeopard way of doing things. 120 IMP oldImp = NULL; 121 if (imp) { 122 oldImp = method->method_imp; 123 method->method_imp = imp; 124 } 125 return oldImp; 126} 127 128void method_exchangeImplementations(Method m1, Method m2) { 129 if (m1 == m2) return; 130 if (!m1 || !m2) return; 131 IMP imp2 = method_getImplementation(m2); 132 IMP imp1 = method_setImplementation(m1, imp2); 133 method_setImplementation(m2, imp1); 134} 135 136struct objc_method_description protocol_getMethodDescription(Protocol *p, 137 SEL aSel, 138 BOOL isRequiredMethod, 139 BOOL isInstanceMethod) { 140 struct objc_method_description *descPtr = NULL; 141 // No such thing as required in ObjC1. 142 if (isInstanceMethod) { 143 descPtr = [p descriptionForInstanceMethod:aSel]; 144 } else { 145 descPtr = [p descriptionForClassMethod:aSel]; 146 } 147 148 struct objc_method_description desc; 149 if (descPtr) { 150 desc = *descPtr; 151 } else { 152 bzero(&desc, sizeof(desc)); 153 } 154 return desc; 155} 156 157BOOL sel_isEqual(SEL lhs, SEL rhs) { 158 // Apple (informally) promises this will work in the future: 159 // http://twitter.com/#!/gparker/status/2400099786 160 return (lhs == rhs) ? YES : NO; 161} 162 163#endif // GTM_MACOS_SDK && (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5)