weak_nsobject.h 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. // Copyright 2013 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. #ifndef BASE_IOS_WEAK_NSOBJECT_H_
  5. #define BASE_IOS_WEAK_NSOBJECT_H_
  6. #import <Foundation/Foundation.h>
  7. #import <objc/runtime.h>
  8. #include "base/check.h"
  9. #include "base/compiler_specific.h"
  10. #include "base/memory/ref_counted.h"
  11. #include "base/threading/thread_checker.h"
  12. // WeakNSObject<> is patterned after scoped_nsobject<>, but instead of
  13. // maintaining ownership of an NSObject subclass object, it will nil itself out
  14. // when the object is deallocated.
  15. //
  16. // WeakNSProtocol<> has the same behavior as WeakNSObject, but can be used
  17. // with protocols.
  18. //
  19. // Example usage (base::WeakNSObject<T>):
  20. // scoped_nsobject<Foo> foo([[Foo alloc] init]);
  21. // WeakNSObject<Foo> weak_foo; // No pointer
  22. // weak_foo.reset(foo) // Now a weak reference is kept.
  23. // [weak_foo description]; // Returns [foo description].
  24. // foo.reset(); // The reference is released.
  25. // [weak_foo description]; // Returns nil, as weak_foo is pointing to nil.
  26. //
  27. //
  28. // Implementation wise a WeakNSObject keeps a reference to a refcounted
  29. // WeakContainer. There is one unique instance of a WeakContainer per watched
  30. // NSObject, this relationship is maintained via the ObjectiveC associated
  31. // object API, indirectly via an ObjectiveC CRBWeakNSProtocolSentinel class.
  32. //
  33. // Threading restrictions:
  34. // - Several WeakNSObject pointing to the same underlying object must all be
  35. // created and dereferenced on the same thread;
  36. // - thread safety is enforced by the implementation, except in two cases:
  37. // (1) it is allowed to copy a WeakNSObject on a different thread. However,
  38. // that copy must return to the original thread before being dereferenced,
  39. // (2) it is allowed to destroy a WeakNSObject on any thread;
  40. // - the implementation assumes that the tracked object will be released on the
  41. // same thread that the WeakNSObject is created on.
  42. namespace base {
  43. // WeakContainer keeps a weak pointer to an object and clears it when it
  44. // receives nullify() from the object's sentinel.
  45. class WeakContainer : public base::RefCountedThreadSafe<WeakContainer> {
  46. public:
  47. explicit WeakContainer(id object);
  48. id object() {
  49. DCHECK(checker_.CalledOnValidThread());
  50. return object_;
  51. }
  52. void nullify() {
  53. DCHECK(checker_.CalledOnValidThread());
  54. object_ = nil;
  55. }
  56. private:
  57. friend base::RefCountedThreadSafe<WeakContainer>;
  58. ~WeakContainer();
  59. base::ThreadChecker checker_;
  60. __unsafe_unretained id object_;
  61. };
  62. } // namespace base
  63. // Sentinel for observing the object contained in the weak pointer. The object
  64. // will be deleted when the weak object is deleted and will notify its
  65. // container.
  66. @interface CRBWeakNSProtocolSentinel : NSObject
  67. // Return the only associated container for this object. There can be only one.
  68. // Will return null if object is nil .
  69. + (scoped_refptr<base::WeakContainer>)containerForObject:(id)object;
  70. @end
  71. namespace base {
  72. // Base class for all WeakNSObject derivatives.
  73. template <typename NST>
  74. class WeakNSProtocol {
  75. public:
  76. explicit WeakNSProtocol(NST object = nil) {
  77. container_ = [CRBWeakNSProtocolSentinel containerForObject:object];
  78. }
  79. WeakNSProtocol(const WeakNSProtocol<NST>& that) {
  80. // A WeakNSProtocol object can be copied on one thread and used on
  81. // another.
  82. checker_.DetachFromThread();
  83. container_ = that.container_;
  84. }
  85. ~WeakNSProtocol() {
  86. // A WeakNSProtocol object can be used on one thread and released on
  87. // another. This is not the case for the contained object.
  88. checker_.DetachFromThread();
  89. }
  90. void reset(NST object = nil) {
  91. DCHECK(checker_.CalledOnValidThread());
  92. container_ = [CRBWeakNSProtocolSentinel containerForObject:object];
  93. }
  94. NST get() const {
  95. DCHECK(checker_.CalledOnValidThread());
  96. if (!container_.get())
  97. return nil;
  98. return container_->object();
  99. }
  100. WeakNSProtocol& operator=(const WeakNSProtocol<NST>& that) {
  101. // A WeakNSProtocol object can be copied on one thread and used on
  102. // another.
  103. checker_.DetachFromThread();
  104. container_ = that.container_;
  105. return *this;
  106. }
  107. bool operator==(NST that) const {
  108. DCHECK(checker_.CalledOnValidThread());
  109. return get() == that;
  110. }
  111. bool operator!=(NST that) const {
  112. DCHECK(checker_.CalledOnValidThread());
  113. return get() != that;
  114. }
  115. operator NST() const {
  116. DCHECK(checker_.CalledOnValidThread());
  117. return get();
  118. }
  119. private:
  120. // Refecounted reference to the container tracking the ObjectiveC object this
  121. // class encapsulates.
  122. scoped_refptr<base::WeakContainer> container_;
  123. base::ThreadChecker checker_;
  124. };
  125. // Free functions
  126. template <class NST>
  127. bool operator==(NST p1, const WeakNSProtocol<NST>& p2) {
  128. return p1 == p2.get();
  129. }
  130. template <class NST>
  131. bool operator!=(NST p1, const WeakNSProtocol<NST>& p2) {
  132. return p1 != p2.get();
  133. }
  134. template <typename NST>
  135. class WeakNSObject : public WeakNSProtocol<NST*> {
  136. public:
  137. explicit WeakNSObject(NST* object = nil) : WeakNSProtocol<NST*>(object) {}
  138. WeakNSObject(const WeakNSObject<NST>& that) : WeakNSProtocol<NST*>(that) {}
  139. WeakNSObject& operator=(const WeakNSObject<NST>& that) {
  140. WeakNSProtocol<NST*>::operator=(that);
  141. return *this;
  142. }
  143. };
  144. // Specialization to make WeakNSObject<id> work.
  145. template <>
  146. class WeakNSObject<id> : public WeakNSProtocol<id> {
  147. public:
  148. explicit WeakNSObject(id object = nil) : WeakNSProtocol<id>(object) {}
  149. WeakNSObject(const WeakNSObject<id>& that) : WeakNSProtocol<id>(that) {}
  150. WeakNSObject& operator=(const WeakNSObject<id>& that) {
  151. WeakNSProtocol<id>::operator=(that);
  152. return *this;
  153. }
  154. };
  155. } // namespace base
  156. #endif // BASE_IOS_WEAK_NSOBJECT_H_