diff options
Diffstat (limited to 'chromium/base/ios/weak_nsobject.h')
-rw-r--r-- | chromium/base/ios/weak_nsobject.h | 189 |
1 files changed, 189 insertions, 0 deletions
diff --git a/chromium/base/ios/weak_nsobject.h b/chromium/base/ios/weak_nsobject.h new file mode 100644 index 00000000000..fc3a7c38dc4 --- /dev/null +++ b/chromium/base/ios/weak_nsobject.h @@ -0,0 +1,189 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// 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/basictypes.h" +#include "base/compiler_specific.h" +#include "base/logging.h" +#include "base/memory/ref_counted.h" +#include "base/threading/non_thread_safe.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) : object_(object) {} + + id object() { + DCHECK(checker_.CalledOnValidThread()); + return object_; + } + + void nullify() { + DCHECK(checker_.CalledOnValidThread()); + object_ = nil; + } + + private: + friend base::RefCountedThreadSafe<WeakContainer>; + ~WeakContainer() {} + base::ThreadChecker checker_; + 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_ |