Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for arrays of more types #5274

Merged
merged 32 commits into from
Sep 23, 2017
Merged

Add support for arrays of more types #5274

merged 32 commits into from
Sep 23, 2017

Conversation

tgoyne
Copy link
Member

@tgoyne tgoyne commented Aug 29, 2017

This is currently targeting a branch with #5267 and latest master merged into master-3.0 for the sake of showing something sensible for review.

All functionality of RLMArray and List should now be supported for all of the Realm-supported data types, except for queries. Currently trying to query primitive lists just silently ignores the predicate passed in. See RLMTestObjects.h for examples of how the models are declared in obj-c (as with RLMObject arrays, generic type parameters can be used but are insufficient). In Swift the expected normal things work (e.g. List<Int?> etc.).

The bulk of the obj-c changes are adjusting how validation is done. Notably unbox() no longer validates its input and instead we validate all values before passing them to the object store. This is needed both for providing sensible error messages without threading even more awful state tracking into RLMAccessorContext, and to avoid duplicating all of the logic for unmanaged objects. The other obj-c changes are just adding support in the KVC and aggregate functions.

Swift changes were simpler; all that was left to do was make more types conform to RealmCollectionValue and make realm collections conditionally define aggregate functions for Lists and Results of aggregatable types.

The tests are unfortunately something of a mess. For obj-c I had the idea of generating tests on each array type from a template using a simple python script. This did not turn out as well as I hoped, and unsurprisingly the python script turned into a terrible pile of hacks and the template file is awful. For Swift I attempted to take the same approach as the C++ objectstore tests, but ran into a lot of issues with the current limitations of Swift generics (most notably the lack of conditional conformances). Both of these probably need to be rethought, but I think that can wait; the tests do at least serve to test the code for now.

tgoyne added 6 commits August 25, 2017 16:26
* tg/list-self-assignment:
  Fix more cases where assigning an RLMArray property to itself would clear the RLMArray
  Fix an issue causing permissions tests to fail
  Update objectstore
  Fix compilation error in Swift 4
These were skipped because prior to fine-grained notifications it was
error-prone and hard to imagine a scenario where it'd be useful, but with
fine-grained notifications it's potentially valuable.
@tgoyne tgoyne self-assigned this Aug 29, 2017
@tgoyne tgoyne requested review from bdash and austinzheng August 29, 2017 21:03
@austinzheng
Copy link
Contributor

Nothing stands out to me as being problematic, it looks good. I'll review it again tomorrow more carefully.

@bdash
Copy link
Contributor

bdash commented Aug 30, 2017

There's a linker error which suggests we'll need a core release including the fix from realm/realm-core#2823:

Undefined symbols for architecture i386:
  "unsigned long realm::Table::find_first<realm::BinaryData>(unsigned long, realm::BinaryData) const", referenced from:
      unsigned long realm::List::find<realm::BinaryData>(realm::BinaryData const&) const in libRealm.a(list.o)
      unsigned long realm::Results::index_of<realm::BinaryData>(realm::BinaryData const&) in libRealm.a(results.o)
ld: symbol(s) not found for architecture i386

Realm/RLMArray.h Outdated
/**
Indicates whether the objects in the collection can be `nil`.
*/
@property (nonatomic, readonly) bool optional;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be BOOL, and should likely also have getter=isOptional to follow Cocoa's naming conventions.

/**
Indicates whether the objects in the collection can be `nil`.
*/
@property (nonatomic, readonly) bool optional;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto for BOOL / getter=isOptional.

return value ? @(*value) : nil;
}

- (void)deleteObjectsFromRealm {
if (_type != RLMPropertyTypeObject) {
@throw RLMException(@"Cannot delete objects from RLMArray<%@>: only RLMObjects can be deleted.", RLMTypeToString(_type));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clearing the array seems close enough in terms of semantics to what happens with arrays containing objects that it may be simpler to do that rather than throwing here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The public API that this is called by (-[RLMRealm deleteObjects:]) can't support deleting collections of non-objects (what would [realm deleteObjects:@[@0]] do?).

_realm.schema, _realm.group);
}
else {
// FIXME
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we just thrown an exception for now?

@@ -64,6 +62,11 @@ typedef NS_ENUM(int32_t, RLMPropertyType);
@property (nonatomic, readonly, assign) RLMPropertyType type;

/**
Indicates whether the objects in the collection can be `nil`.
*/
@property (nonatomic, readonly) bool optional;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto about BOOL / getter=isOptional.

@@ -328,6 +336,7 @@ - (RLMResults *)objectsWithPredicate:(NSPredicate *)predicate {
if (_results.get_mode() == Results::Mode::Empty) {
return self;
}
// FIXME: primitive array queries
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we throw for now rather than silently giving incorrect results?

@bdash bdash changed the base branch from tg/primitive-array-base to master-3.0 September 18, 2017 23:32
… of primitives

There's a disagreement between Swift 3.1 and 3.2 as to whether `Element`
or `ElementType` should be used in the constraints, and I've been unable
to find one approach that works for both.
`-[NSData compare:]` doesn't exist, so resort to comparing `NSData`
instances using `memcmp`. Using `-compare:` happened to work on macOS
because a system framework provided an implementation in a category. No
such luck on iOS, tvOS and watchOS though.
@bdash
Copy link
Contributor

bdash commented Sep 19, 2017

One problem the tests reveal with Xcode 9 / Swift 4 is:

Simultaneous accesses to 0x6040000de518, but modification requires exclusive access.
Previous access (a modification) started at RealmSwift Tests`implicit closure #1 in PrimitiveListTests.testReplaceRange() + 209 (0x120c8fa21).
Current access (a read) started at:
0    libswiftCore.dylib                 0x00000001219418e0 swift_beginAccess + 605
1    RealmSwift Tests                   0x0000000120c77a40 PrimitiveListTestsBase.array.getter + 68
2    RealmSwift Tests                   0x0000000120c8e0c0 PrimitiveListTests.testReplaceRange() + 1114
3    RealmSwift Tests                   0x0000000120c8ff20 @objc PrimitiveListTests.testReplaceRange() + 36

This error occurs during the evaluation of:

array.replaceSubrange(0..<0, with: [values[0]])

I think Swift's new exclusive access checking isn't safe against Objective-C / C++ exceptions being thrown, so the earlier:

assertThrows(array.replaceSubrange(0..<1, with: []),
             reason: "Index 0 is out of bounds")

leaves the access checking state in an inconsistent state.


I've disabled the problematic assertThrows in df38d3a for now.

`XCTestSuite.defaultTestSuite` changed from a function to a property in
Swift 4.
Tagged pointers aren't enabled on all systems, and there's no guarantee
when they'll be used either.
@bdash bdash force-pushed the tg/primitive-array branch from 7c8059e to df38d3a Compare September 19, 2017 03:06
Different versions of Swift have differing opinions as to whether these
methods override methods with the same name from `TestCase`. Work around
this by renaming the methods.
Swift 3.0 didn't allow bridging between `NSNumber` and sized integer types
such as `Int8`. We need to use `dynamicBridgeCast` to get the correct
bridging for those types.
`@testable` doesn't work with our Release configuration.
explicitly suppress documentation on a few internal methods.
@bdash bdash force-pushed the tg/primitive-array branch from 4b38ceb to 699c298 Compare September 19, 2017 22:48
@bdash
Copy link
Contributor

bdash commented Sep 20, 2017

All of the remaining CI failures are due to flakiness.

@bdash
Copy link
Contributor

bdash commented Sep 21, 2017

The work remaining here appears to be:

  • Change log entry
  • Another review pass from all involved to determine if there's any other remaining work

@bdash bdash added this to the RMP 2.0 milestone Sep 22, 2017
* origin/master-3.0:
  Remove `List` conformance to `RangeReplaceableCollection`
  Add compatibility for ROS 2 user info API
@@ -10,3 +10,5 @@ DEFINES_MODULE = YES;
INFOPLIST_FILE = RealmSwift/RealmSwift-Info.plist;
PRODUCT_NAME = RealmSwift;
PRODUCT_BUNDLE_IDENTIFIER = io.realm.RealmSwit;

OTHER_SWIFT_FLAGS = -D BUILDING_REALM_SWIFT;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't this need to be defined in the podspec as well?

If that's difficult then inverting the condition would avoid that.

Copy link
Contributor

@bdash bdash Sep 22, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume it would. I'm quite surprised that the CocoaPods jobs succeeded without it!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It succeeded because the Swift compiler only emits a warning about the redundant import. I went ahead and inverted the condition in e1b6c8d anyway.

determining if it should import RealmSwift.

This ensures it does the right thing when building via CocoaPods.
@bdash
Copy link
Contributor

bdash commented Sep 23, 2017

The failing Swift test has already been fixed on master-3.0.

* origin/master-3.0:
  Update ROS testing dependency, reenable tests (#5332)
  Update a test case now that a more precise error is being raised.
  Fix changelog
  Have +schemaVersionAtURL: do a better job of translating any exceptions that are thrown.
  Add a change log entry.
  Satisfy SwiftLint.
  Add Swift support.
  Add a test of offline client reset.
  Handle incompatible synced Realm exceptions.
@tgoyne
Copy link
Member Author

tgoyne commented Sep 23, 2017

Obj-C and Swift tests now pass for me locally on both macOS and on my phone, so I think any remaining failures are just CI flakiness.

@tgoyne tgoyne merged commit 8b87751 into master-3.0 Sep 23, 2017
@bmunkholm bmunkholm deleted the tg/primitive-array branch March 12, 2019 13:05
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 15, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants