diff --git a/src/core/macfslistener.mm b/src/core/macfslistener.mm index cf799bd89..4ae6c5d5a 100644 --- a/src/core/macfslistener.mm +++ b/src/core/macfslistener.mm @@ -5,6 +5,7 @@ #include #include "core/logging.h" +#include "core/scoped_nsobject.h" MacFSListener::MacFSListener(QObject* parent) : QObject(parent), @@ -40,6 +41,7 @@ void MacFSListener::AddPath(const QString& path) { void MacFSListener::UpdateStream() { if (stream_) { FSEventStreamInvalidate(stream_); + FSEventStreamRelease(stream_); stream_ = NULL; } @@ -47,12 +49,12 @@ void MacFSListener::UpdateStream() { return; } - NSMutableArray* array = [[NSMutableArray alloc] init]; + scoped_nsobject array([[NSMutableArray alloc] init]); foreach (const QString& path, paths_) { - NSString* string = [[NSString alloc] initWithUTF8String: path.toUtf8().constData()]; - [array addObject: string]; - [string release]; + scoped_nsobject string( + [[NSString alloc] initWithUTF8String: path.toUtf8().constData()]); + [array addObject: string.get()]; } FSEventStreamContext context; @@ -64,13 +66,11 @@ void MacFSListener::UpdateStream() { NULL, &EventStreamCallback, &context, // Copied - (CFArrayRef)array, + reinterpret_cast(array.get()), kFSEventStreamEventIdSinceNow, latency, kFSEventStreamCreateFlagNone); FSEventStreamScheduleWithRunLoop(stream_, run_loop_, kCFRunLoopDefaultMode); FSEventStreamStart(stream_); - - [array release]; } diff --git a/src/core/scoped_nsobject.h b/src/core/scoped_nsobject.h new file mode 100644 index 000000000..cd8271399 --- /dev/null +++ b/src/core/scoped_nsobject.h @@ -0,0 +1,160 @@ +// Copyright (c) 2011 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_MEMORY_SCOPED_NSOBJECT_H_ +#define BASE_MEMORY_SCOPED_NSOBJECT_H_ + +#import + +// scoped_nsobject<> is patterned after scoped_ptr<>, but maintains ownership +// of an NSObject subclass object. Style deviations here are solely for +// compatibility with scoped_ptr<>'s interface, with which everyone is already +// familiar. +// +// When scoped_nsobject<> takes ownership of an object (in the constructor or +// in reset()), it takes over the caller's existing ownership claim. The +// caller must own the object it gives to scoped_nsobject<>, and relinquishes +// an ownership claim to that object. scoped_nsobject<> does not call +// -retain. +// +// scoped_nsobject<> is not to be used for NSAutoreleasePools. For +// NSAutoreleasePools use ScopedNSAutoreleasePool from +// scoped_nsautorelease_pool.h instead. +// We check for bad uses of scoped_nsobject and NSAutoreleasePool at compile +// time with a template specialization (see below). +template +class scoped_nsobject { + public: + explicit scoped_nsobject(NST* object = nil) + : object_(object) { + } + + ~scoped_nsobject() { + [object_ release]; + } + + void reset(NST* object = nil) { + // We intentionally do not check that object != object_ as the caller must + // already have an ownership claim over whatever it gives to + // scoped_nsobject and ScopedCFTypeRef, whether it's in the constructor or + // in a call to reset(). In either case, it relinquishes that claim and + // the scoper assumes it. + [object_ release]; + object_ = object; + } + + bool operator==(NST* that) const { return object_ == that; } + bool operator!=(NST* that) const { return object_ != that; } + + operator NST*() const { + return object_; + } + + NST* get() const { + return object_; + } + + void swap(scoped_nsobject& that) { + NST* temp = that.object_; + that.object_ = object_; + object_ = temp; + } + + // scoped_nsobject<>::release() is like scoped_ptr<>::release. It is NOT + // a wrapper for [object_ release]. To force a scoped_nsobject<> object to + // call [object_ release], use scoped_nsobject<>::reset(). + NST* release() __attribute__((warn_unused_result)) { + NST* temp = object_; + object_ = nil; + return temp; + } + + private: + NST* object_; + + Q_DISABLE_COPY(scoped_nsobject); +}; + +// Free functions +template +void swap(scoped_nsobject& p1, scoped_nsobject& p2) { + p1.swap(p2); +} + +template +bool operator==(C* p1, const scoped_nsobject& p2) { + return p1 == p2.get(); +} + +template +bool operator!=(C* p1, const scoped_nsobject& p2) { + return p1 != p2.get(); +} + + +// Specialization to make scoped_nsobject work. +template<> +class scoped_nsobject { + public: + explicit scoped_nsobject(id object = nil) + : object_(object) { + } + + ~scoped_nsobject() { + [object_ release]; + } + + void reset(id object = nil) { + // We intentionally do not check that object != object_ as the caller must + // already have an ownership claim over whatever it gives to + // scoped_nsobject and ScopedCFTypeRef, whether it's in the constructor or + // in a call to reset(). In either case, it relinquishes that claim and + // the scoper assumes it. + [object_ release]; + object_ = object; + } + + bool operator==(id that) const { return object_ == that; } + bool operator!=(id that) const { return object_ != that; } + + operator id() const { + return object_; + } + + id get() const { + return object_; + } + + void swap(scoped_nsobject& that) { + id temp = that.object_; + that.object_ = object_; + object_ = temp; + } + + // scoped_nsobject<>::release() is like scoped_ptr<>::release. It is NOT + // a wrapper for [object_ release]. To force a scoped_nsobject<> object to + // call [object_ release], use scoped_nsobject<>::reset(). + id release() __attribute__((warn_unused_result)) { + id temp = object_; + object_ = nil; + return temp; + } + + private: + id object_; + + Q_DISABLE_COPY(scoped_nsobject); +}; + +// Do not use scoped_nsobject for NSAutoreleasePools, use +// ScopedNSAutoreleasePool instead. This is a compile time check. See details +// at top of header. +template<> +class scoped_nsobject { + private: + explicit scoped_nsobject(NSAutoreleasePool* object = nil); + Q_DISABLE_COPY(scoped_nsobject); +}; + +#endif // BASE_MEMORY_SCOPED_NSOBJECT_H_