RLMThreadSafeReference.mm 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. ////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright 2016 Realm Inc.
  4. //
  5. // Licensed under the Apache License, Version 2.0 (the "License");
  6. // you may not use this file except in compliance with the License.
  7. // You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing, software
  12. // distributed under the License is distributed on an "AS IS" BASIS,
  13. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. // See the License for the specific language governing permissions and
  15. // limitations under the License.
  16. //
  17. ////////////////////////////////////////////////////////////////////////////
  18. #import "RLMThreadSafeReference_Private.hpp"
  19. #import "RLMUtil.hpp"
  20. template<typename Function>
  21. static auto translateErrors(Function&& f) {
  22. try {
  23. return f();
  24. }
  25. catch (std::exception const& e) {
  26. @throw RLMException(e);
  27. }
  28. }
  29. @implementation RLMThreadSafeReference {
  30. std::unique_ptr<realm::ThreadSafeReferenceBase> _reference;
  31. id _metadata;
  32. Class _type;
  33. }
  34. - (instancetype)initWithThreadConfined:(id<RLMThreadConfined>)threadConfined {
  35. if (!(self = [super init])) {
  36. return nil;
  37. }
  38. REALM_ASSERT_DEBUG([threadConfined conformsToProtocol:@protocol(RLMThreadConfined)]);
  39. if (![threadConfined conformsToProtocol:@protocol(RLMThreadConfined_Private)]) {
  40. @throw RLMException(@"Illegal custom conformance to `RLMThreadConfined` by `%@`", threadConfined.class);
  41. } else if (threadConfined.invalidated) {
  42. @throw RLMException(@"Cannot construct reference to invalidated object");
  43. } else if (!threadConfined.realm) {
  44. @throw RLMException(@"Cannot construct reference to unmanaged object, "
  45. "which can be passed across threads directly");
  46. }
  47. translateErrors([&] {
  48. _reference = [(id<RLMThreadConfined_Private>)threadConfined makeThreadSafeReference];
  49. _metadata = ((id<RLMThreadConfined_Private>)threadConfined).objectiveCMetadata;
  50. });
  51. _type = threadConfined.class;
  52. return self;
  53. }
  54. + (instancetype)referenceWithThreadConfined:(id<RLMThreadConfined>)threadConfined {
  55. return [[self alloc] initWithThreadConfined:threadConfined];
  56. }
  57. - (id<RLMThreadConfined>)resolveReferenceInRealm:(RLMRealm *)realm {
  58. if (!_reference) {
  59. @throw RLMException(@"Can only resolve a thread safe reference once.");
  60. }
  61. return translateErrors([&] {
  62. return [_type objectWithThreadSafeReference:std::move(_reference) metadata:_metadata realm:realm];
  63. });
  64. }
  65. - (BOOL)isInvalidated {
  66. return !_reference;
  67. }
  68. @end