Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
scoped_nsobject.h
Go to the documentation of this file.
1// Copyright 2013 The Flutter 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
5#ifndef FLUTTER_FML_PLATFORM_DARWIN_SCOPED_NSOBJECT_H_
6#define FLUTTER_FML_PLATFORM_DARWIN_SCOPED_NSOBJECT_H_
7
8#include <type_traits>
9#include <utility>
10
11// Include NSObject.h directly because Foundation.h pulls in many dependencies.
12// (Approx 100k lines of code versus 1.5k for NSObject.h). scoped_nsobject gets
13// singled out because it is most typically included from other header files.
14#import <Foundation/NSObject.h>
15
16#include "flutter/fml/compiler_specific.h"
17#include "flutter/fml/macros.h"
18#include "flutter/fml/platform/darwin/scoped_typeref.h"
19
20#if !defined(__has_feature) || !__has_feature(objc_arc)
21@class NSAutoreleasePool;
22#endif
23
24namespace fml {
25
26// scoped_nsobject<> is patterned after scoped_ptr<>, but maintains ownership
27// of an NSObject subclass object. Style deviations here are solely for
28// compatibility with scoped_ptr<>'s interface, with which everyone is already
29// familiar.
30//
31// scoped_nsobject<> takes ownership of an object (in the constructor or in
32// reset()) by taking over the caller's existing ownership claim. The caller
33// must own the object it gives to scoped_nsobject<>, and relinquishes an
34// ownership claim to that object. scoped_nsobject<> does not call -retain,
35// callers have to call this manually if appropriate.
36//
37// scoped_nsprotocol<> has the same behavior as scoped_nsobject, but can be used
38// with protocols.
39//
40// scoped_nsobject<> is not to be used for NSAutoreleasePools. For
41// NSAutoreleasePools use ScopedNSAutoreleasePool from
42// scoped_nsautorelease_pool.h instead.
43// We check for bad uses of scoped_nsobject and NSAutoreleasePool at compile
44// time with a template specialization (see below).
45//
46// If Automatic Reference Counting (aka ARC) is enabled then the ownership
47// policy is not controllable by the user as ARC make it really difficult to
48// transfer ownership (the reference passed to scoped_nsobject constructor is
49// sunk by ARC and __attribute((ns_consumed)) appears to not work correctly
50// with Objective-C++ see https://llvm.org/bugs/show_bug.cgi?id=27887). Due to
51// that, the policy is always to |RETAIN| when using ARC.
52
53namespace internal {
54
55id ScopedNSProtocolTraitsRetain(__unsafe_unretained id obj)
56 __attribute((ns_returns_not_retained));
57id ScopedNSProtocolTraitsAutoRelease(__unsafe_unretained id obj)
58 __attribute((ns_returns_not_retained));
59void ScopedNSProtocolTraitsRelease(__unsafe_unretained id obj);
60
61// Traits for ScopedTypeRef<>. As this class may be compiled from file with
62// Automatic Reference Counting enable or not all methods have annotation to
63// enforce the same code generation in both case (in particular, the Retain
64// method uses ns_returns_not_retained to prevent ARC to insert a -release
65// call on the returned value and thus defeating the -retain).
66template <typename NST>
68 static NST InvalidValue() __attribute((ns_returns_not_retained)) {
69 return nil;
70 }
71 static NST Retain(__unsafe_unretained NST nst)
72 __attribute((ns_returns_not_retained)) {
74 }
75 static void Release(__unsafe_unretained NST nst) {
77 }
78};
79
80} // namespace internal
81
82template <typename NST>
84 : public ScopedTypeRef<NST, internal::ScopedNSProtocolTraits<NST>> {
85 public:
87
88#if !defined(__has_feature) || !__has_feature(objc_arc)
93#else
94 explicit scoped_nsprotocol(NST object = Traits::InvalidValue())
95 : ScopedTypeRef<NST, Traits>(object,
96 scoped_policy::OwnershipPolicy::kRetain) {}
97#endif
98
99 // NOLINTNEXTLINE(google-explicit-constructor)
102
103 template <typename NSR>
104 explicit scoped_nsprotocol(const scoped_nsprotocol<NSR>& that_as_subclass)
105 : ScopedTypeRef<NST, Traits>(that_as_subclass) {}
106
107 // NOLINTNEXTLINE(google-explicit-constructor)
110
115
116#if !defined(__has_feature) || !__has_feature(objc_arc)
122#else
123 void reset(NST object = Traits::InvalidValue()) {
126 }
127#endif
128
129 // Shift reference to the autorelease pool to be released later.
130 NST autorelease() __attribute((ns_returns_not_retained)) {
132 }
133};
134
135// Free functions
136template <class C>
138 p1.swap(p2);
139}
140
141template <class C>
142bool operator==(C p1, const scoped_nsprotocol<C>& p2) {
143 return p1 == p2.get();
144}
145
146template <class C>
147bool operator!=(C p1, const scoped_nsprotocol<C>& p2) {
148 return p1 != p2.get();
149}
150
151template <typename NST>
152class scoped_nsobject : public scoped_nsprotocol<NST*> {
153 public:
155
156#if !defined(__has_feature) || !__has_feature(objc_arc)
157 explicit scoped_nsobject(NST* object = Traits::InvalidValue(),
160 : scoped_nsprotocol<NST*>(object, policy) {}
161#else
162 explicit scoped_nsobject(NST* object = Traits::InvalidValue())
163 : scoped_nsprotocol<NST*>(object) {}
164#endif
165
166 // NOLINTNEXTLINE(google-explicit-constructor)
168 : scoped_nsprotocol<NST*>(that) {}
169
170 template <typename NSR>
171 explicit scoped_nsobject(const scoped_nsobject<NSR>& that_as_subclass)
172 : scoped_nsprotocol<NST*>(that_as_subclass) {}
173
174 // NOLINTNEXTLINE(google-explicit-constructor)
176 : scoped_nsprotocol<NST*>(std::move(that)) {}
177
180 return *this;
181 }
182
183#if !defined(__has_feature) || !__has_feature(objc_arc)
184 void reset(NST* object = Traits::InvalidValue(),
187 scoped_nsprotocol<NST*>::reset(object, policy);
188 }
189#else
190 void reset(NST* object = Traits::InvalidValue()) {
192 }
193#endif
194
195#if !defined(__has_feature) || !__has_feature(objc_arc)
196 static_assert(std::is_same<NST, NSAutoreleasePool>::value == false,
197 "Use ScopedNSAutoreleasePool instead");
198#endif
199};
200
201// Specialization to make scoped_nsobject<id> work.
202template <>
204 public:
206
207#if !defined(__has_feature) || !__has_feature(objc_arc)
208 explicit scoped_nsobject(id object = Traits::InvalidValue(),
211 : scoped_nsprotocol<id>(object, policy) {}
212#else
213 explicit scoped_nsobject(id object = Traits::InvalidValue())
214 : scoped_nsprotocol<id>(object) {}
215#endif
216
217 // NOLINTNEXTLINE(google-explicit-constructor)
220
221 template <typename NSR>
222 explicit scoped_nsobject(const scoped_nsobject<NSR>& that_as_subclass)
223 : scoped_nsprotocol<id>(that_as_subclass) {}
224
225 // NOLINTNEXTLINE(google-explicit-constructor)
228
231 return *this;
232 }
233
234#if !defined(__has_feature) || !__has_feature(objc_arc)
235 void reset(id object = Traits::InvalidValue(),
238 scoped_nsprotocol<id>::reset(object, policy);
239 }
240#else
241 void reset(id object = Traits::InvalidValue()) {
243 }
244#endif
245};
246
247} // namespace fml
248
249#endif // FLUTTER_FML_PLATFORM_DARWIN_SCOPED_NSOBJECT_H_
m reset()
T get() const __attribute((ns_returns_not_retained))
ScopedTypeRef & operator=(const ScopedTypeRef< T, Traits > &that)
void reset(__unsafe_unretained T object=Traits::InvalidValue(), fml::scoped_policy::OwnershipPolicy policy=fml::scoped_policy::kAssume)
void swap(ScopedTypeRef &that)
scoped_nsobject(id object=Traits::InvalidValue(), scoped_policy::OwnershipPolicy policy=scoped_policy::OwnershipPolicy::kAssume)
scoped_nsobject(const scoped_nsobject< id > &that)
typename scoped_nsprotocol< id >::Traits Traits
void reset(id object=Traits::InvalidValue(), scoped_policy::OwnershipPolicy policy=scoped_policy::OwnershipPolicy::kAssume)
scoped_nsobject(const scoped_nsobject< NSR > &that_as_subclass)
scoped_nsobject & operator=(const scoped_nsobject< id > &that)
scoped_nsobject(scoped_nsobject< id > &&that)
scoped_nsobject & operator=(const scoped_nsobject< NST > &that)
typename scoped_nsprotocol< NST * >::Traits Traits
scoped_nsobject(const scoped_nsobject< NST > &that)
void reset(NST *object=Traits::InvalidValue(), scoped_policy::OwnershipPolicy policy=scoped_policy::OwnershipPolicy::kAssume)
scoped_nsobject(scoped_nsobject< NST > &&that)
scoped_nsobject(const scoped_nsobject< NSR > &that_as_subclass)
scoped_nsobject(NST *object=Traits::InvalidValue(), scoped_policy::OwnershipPolicy policy=scoped_policy::OwnershipPolicy::kAssume)
scoped_nsprotocol & operator=(const scoped_nsprotocol< NST > &that)
scoped_nsprotocol(scoped_nsprotocol< NST > &&that)
scoped_nsprotocol(const scoped_nsprotocol< NSR > &that_as_subclass)
void reset(NST object=Traits::InvalidValue(), scoped_policy::OwnershipPolicy policy=scoped_policy::OwnershipPolicy::kAssume)
scoped_nsprotocol(const scoped_nsprotocol< NST > &that)
scoped_nsprotocol(NST object=Traits::InvalidValue(), scoped_policy::OwnershipPolicy policy=scoped_policy::OwnershipPolicy::kAssume)
internal::ScopedNSProtocolTraits< NST > Traits
NST autorelease() __attribute((ns_returns_not_retained))
void ScopedNSProtocolTraitsRelease(__unsafe_unretained id obj)
id ScopedNSProtocolTraitsAutoRelease(__unsafe_unretained id obj) __attribute((ns_returns_not_retained))
id ScopedNSProtocolTraitsRetain(__unsafe_unretained id obj) __attribute((ns_returns_not_retained))
bool operator==(C p1, const scoped_nsprotocol< C > &p2)
void swap(scoped_nsprotocol< C > &p1, scoped_nsprotocol< C > &p2)
bool operator!=(C p1, const scoped_nsprotocol< C > &p2)
Definition ref_ptr.h:256
static void Release(__unsafe_unretained NST nst)
static NST InvalidValue() __attribute((ns_returns_not_retained))
static NST Retain(__unsafe_unretained NST nst) __attribute((ns_returns_not_retained))
const uintptr_t id