scoped_objc_class_swizzler.mm 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. // Copyright 2014 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #import "base/mac/scoped_objc_class_swizzler.h"
  5. #include <string.h>
  6. #include "base/check_op.h"
  7. namespace base::mac {
  8. ScopedObjCClassSwizzler::ScopedObjCClassSwizzler(Class target,
  9. Class source,
  10. SEL selector)
  11. : old_selector_impl_(NULL), new_selector_impl_(NULL) {
  12. Init(target, source, selector, selector);
  13. }
  14. ScopedObjCClassSwizzler::ScopedObjCClassSwizzler(Class target,
  15. SEL original,
  16. SEL alternate)
  17. : old_selector_impl_(NULL), new_selector_impl_(NULL) {
  18. Init(target, target, original, alternate);
  19. }
  20. ScopedObjCClassSwizzler::~ScopedObjCClassSwizzler() {
  21. if (old_selector_impl_ && new_selector_impl_)
  22. method_exchangeImplementations(old_selector_impl_, new_selector_impl_);
  23. }
  24. IMP ScopedObjCClassSwizzler::GetOriginalImplementation() const {
  25. // Note that while the swizzle is in effect the "new" method is actually
  26. // pointing to the original implementation, since they have been swapped.
  27. return method_getImplementation(new_selector_impl_);
  28. }
  29. void ScopedObjCClassSwizzler::Init(Class target,
  30. Class source,
  31. SEL original,
  32. SEL alternate) {
  33. old_selector_impl_ = class_getInstanceMethod(target, original);
  34. new_selector_impl_ = class_getInstanceMethod(source, alternate);
  35. if (!old_selector_impl_ && !new_selector_impl_) {
  36. // Try class methods.
  37. old_selector_impl_ = class_getClassMethod(target, original);
  38. new_selector_impl_ = class_getClassMethod(source, alternate);
  39. }
  40. DCHECK(old_selector_impl_);
  41. DCHECK(new_selector_impl_);
  42. if (!old_selector_impl_ || !new_selector_impl_)
  43. return;
  44. // The argument and return types must match exactly.
  45. const char* old_types = method_getTypeEncoding(old_selector_impl_);
  46. const char* new_types = method_getTypeEncoding(new_selector_impl_);
  47. DCHECK(old_types);
  48. DCHECK(new_types);
  49. DCHECK_EQ(0, strcmp(old_types, new_types));
  50. if (!old_types || !new_types || strcmp(old_types, new_types)) {
  51. old_selector_impl_ = new_selector_impl_ = NULL;
  52. return;
  53. }
  54. method_exchangeImplementations(old_selector_impl_, new_selector_impl_);
  55. }
  56. } // namespace base::mac