| // Copyright 2013 The Chromium Authors | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #ifndef BASE_IOS_WEAK_NSOBJECT_H_ | 
 | #define BASE_IOS_WEAK_NSOBJECT_H_ | 
 |  | 
 | #import <Foundation/Foundation.h> | 
 | #import <objc/runtime.h> | 
 |  | 
 | #include "base/check.h" | 
 | #include "base/compiler_specific.h" | 
 | #include "base/memory/ref_counted.h" | 
 | #include "base/threading/thread_checker.h" | 
 |  | 
 | // WeakNSObject<> is patterned after scoped_nsobject<>, but instead of | 
 | // maintaining ownership of an NSObject subclass object, it will nil itself out | 
 | // when the object is deallocated. | 
 | // | 
 | // WeakNSProtocol<> has the same behavior as WeakNSObject, but can be used | 
 | // with protocols. | 
 | // | 
 | // Example usage (base::WeakNSObject<T>): | 
 | //   scoped_nsobject<Foo> foo([[Foo alloc] init]); | 
 | //   WeakNSObject<Foo> weak_foo;  // No pointer | 
 | //   weak_foo.reset(foo)  // Now a weak reference is kept. | 
 | //   [weak_foo description];  // Returns [foo description]. | 
 | //   foo.reset();  // The reference is released. | 
 | //   [weak_foo description];  // Returns nil, as weak_foo is pointing to nil. | 
 | // | 
 | // | 
 | // Implementation wise a WeakNSObject keeps a reference to a refcounted | 
 | // WeakContainer. There is one unique instance of a WeakContainer per watched | 
 | // NSObject, this relationship is maintained via the ObjectiveC associated | 
 | // object API, indirectly via an ObjectiveC CRBWeakNSProtocolSentinel class. | 
 | // | 
 | // Threading restrictions: | 
 | // - Several WeakNSObject pointing to the same underlying object must all be | 
 | //   created and dereferenced on the same thread; | 
 | // - thread safety is enforced by the implementation, except in two cases: | 
 | //   (1) it is allowed to copy a WeakNSObject on a different thread. However, | 
 | //       that copy must return to the original thread before being dereferenced, | 
 | //   (2) it is allowed to destroy a WeakNSObject on any thread; | 
 | // - the implementation assumes that the tracked object will be released on the | 
 | //   same thread that the WeakNSObject is created on. | 
 | namespace base { | 
 |  | 
 | // WeakContainer keeps a weak pointer to an object and clears it when it | 
 | // receives nullify() from the object's sentinel. | 
 | class WeakContainer : public base::RefCountedThreadSafe<WeakContainer> { | 
 |  public: | 
 |   explicit WeakContainer(id object); | 
 |  | 
 |   id object() { | 
 |     DCHECK(checker_.CalledOnValidThread()); | 
 |     return object_; | 
 |   } | 
 |  | 
 |   void nullify() { | 
 |     DCHECK(checker_.CalledOnValidThread()); | 
 |     object_ = nil; | 
 |   } | 
 |  | 
 |  private: | 
 |   friend base::RefCountedThreadSafe<WeakContainer>; | 
 |   ~WeakContainer(); | 
 |   base::ThreadChecker checker_; | 
 |   __unsafe_unretained id object_; | 
 | }; | 
 |  | 
 | }  // namespace base | 
 |  | 
 | // Sentinel for observing the object contained in the weak pointer. The object | 
 | // will be deleted when the weak object is deleted and will notify its | 
 | // container. | 
 | @interface CRBWeakNSProtocolSentinel : NSObject | 
 | // Return the only associated container for this object. There can be only one. | 
 | // Will return null if object is nil . | 
 | + (scoped_refptr<base::WeakContainer>)containerForObject:(id)object; | 
 | @end | 
 |  | 
 | namespace base { | 
 |  | 
 | // Base class for all WeakNSObject derivatives. | 
 | template <typename NST> | 
 | class WeakNSProtocol { | 
 |  public: | 
 |   explicit WeakNSProtocol(NST object = nil) { | 
 |     container_ = [CRBWeakNSProtocolSentinel containerForObject:object]; | 
 |   } | 
 |  | 
 |   WeakNSProtocol(const WeakNSProtocol<NST>& that) { | 
 |     // A WeakNSProtocol object can be copied on one thread and used on | 
 |     // another. | 
 |     checker_.DetachFromThread(); | 
 |     container_ = that.container_; | 
 |   } | 
 |  | 
 |   ~WeakNSProtocol() { | 
 |     // A WeakNSProtocol object can be used on one thread and released on | 
 |     // another. This is not the case for the contained object. | 
 |     checker_.DetachFromThread(); | 
 |   } | 
 |  | 
 |   void reset(NST object = nil) { | 
 |     DCHECK(checker_.CalledOnValidThread()); | 
 |     container_ = [CRBWeakNSProtocolSentinel containerForObject:object]; | 
 |   } | 
 |  | 
 |   NST get() const { | 
 |     DCHECK(checker_.CalledOnValidThread()); | 
 |     if (!container_.get()) | 
 |       return nil; | 
 |     return container_->object(); | 
 |   } | 
 |  | 
 |   WeakNSProtocol& operator=(const WeakNSProtocol<NST>& that) { | 
 |     // A WeakNSProtocol object can be copied on one thread and used on | 
 |     // another. | 
 |     checker_.DetachFromThread(); | 
 |     container_ = that.container_; | 
 |     return *this; | 
 |   } | 
 |  | 
 |   bool operator==(NST that) const { | 
 |     DCHECK(checker_.CalledOnValidThread()); | 
 |     return get() == that; | 
 |   } | 
 |  | 
 |   bool operator!=(NST that) const { | 
 |     DCHECK(checker_.CalledOnValidThread()); | 
 |     return get() != that; | 
 |   } | 
 |  | 
 |   operator NST() const { | 
 |     DCHECK(checker_.CalledOnValidThread()); | 
 |     return get(); | 
 |   } | 
 |  | 
 |  private: | 
 |   // Refecounted reference to the container tracking the ObjectiveC object this | 
 |   // class encapsulates. | 
 |   scoped_refptr<base::WeakContainer> container_; | 
 |   base::ThreadChecker checker_; | 
 | }; | 
 |  | 
 | // Free functions | 
 | template <class NST> | 
 | bool operator==(NST p1, const WeakNSProtocol<NST>& p2) { | 
 |   return p1 == p2.get(); | 
 | } | 
 |  | 
 | template <class NST> | 
 | bool operator!=(NST p1, const WeakNSProtocol<NST>& p2) { | 
 |   return p1 != p2.get(); | 
 | } | 
 |  | 
 | template <typename NST> | 
 | class WeakNSObject : public WeakNSProtocol<NST*> { | 
 |  public: | 
 |   explicit WeakNSObject(NST* object = nil) : WeakNSProtocol<NST*>(object) {} | 
 |  | 
 |   WeakNSObject(const WeakNSObject<NST>& that) : WeakNSProtocol<NST*>(that) {} | 
 |  | 
 |   WeakNSObject& operator=(const WeakNSObject<NST>& that) { | 
 |     WeakNSProtocol<NST*>::operator=(that); | 
 |     return *this; | 
 |   } | 
 | }; | 
 |  | 
 | // Specialization to make WeakNSObject<id> work. | 
 | template <> | 
 | class WeakNSObject<id> : public WeakNSProtocol<id> { | 
 |  public: | 
 |   explicit WeakNSObject(id object = nil) : WeakNSProtocol<id>(object) {} | 
 |  | 
 |   WeakNSObject(const WeakNSObject<id>& that) : WeakNSProtocol<id>(that) {} | 
 |  | 
 |   WeakNSObject& operator=(const WeakNSObject<id>& that) { | 
 |     WeakNSProtocol<id>::operator=(that); | 
 |     return *this; | 
 |   } | 
 | }; | 
 |  | 
 | }  // namespace base | 
 |  | 
 | #endif  // BASE_IOS_WEAK_NSOBJECT_H_ |