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

Crashes after making property optional #3732

Closed
BObereder opened this issue Jun 9, 2016 · 5 comments
Closed

Crashes after making property optional #3732

BObereder opened this issue Jun 9, 2016 · 5 comments
Assignees
Labels

Comments

@BObereder
Copy link

BObereder commented Jun 9, 2016

Goals

Hi,
we wanted to make a property optional and are experiencing some crashes.
We had a NSDate property non optional for a long time like this:
public dynamic var dateSaved: NSDate = NSDate(timeIntervalSince1970: 0)
and now we made it optional like this:
public dynamic var dateSaved: NSDate?

Usually this should work without any problems, just bump the schemaVersion and add an empty migration block.
Here was the first hurdle we had to add a migration since it was crashing. So we added the following migration.

Code Sample

if oldSchemaVersion < 13 {
  migration.enumerate(Post.className()) { oldObject, newObject in
    if let oldDateSaved = oldObject?["dateSaved"] as? NSDate {
       newObject?["dateSaved"] = oldDateSaved.timeIntervalSince1970 > 0 ? oldDateSaved : nil
    }
  }
}

Everything seemed fine. Migration worked.

Actual Results

Now in the release we have some crashes that we can not reproduce.
It crashes on this line:
if let oldDateSaved = oldObject?["dateSaved"] as? NSDate {
With this error:
Fatal Exception: RLMException
Invalid property name dateSaved for class Post.

Stack Trace

Fatal Exception: RLMException
0  CoreFoundation                 0x180ed2db0 __exceptionPreprocess
1  libobjc.A.dylib                0x180537f80 objc_exception_throw
2  Realm                          0x100d67bc8 RLMValidatedGetProperty (RLMAccessor.mm:864)
3  RealmSwift                     0x100a327fc specialized Object.subscript.getter (Object.swift:186)
4  RealmSwift                     0x100a2fa30 Object.subscript.getter (Object.swift:182)
5  StylightKit2                   0x10111c15c static StylightKit.(runRealmMigrations(Migration, oldSchemaVersion : UInt64) -> ()).(closure #15) (StylightKit+RealmMigrations.swift:172)
6  Realm                          0x100d77458 -[RLMMigration enumerateObjects:block:] (RLMMigration.mm:82)
7  RealmSwift                     0x100a2e754 Migration.enumerate(String, (oldObject : DynamicObject?, newObject : DynamicObject?) -> ()) -> () (Migration.swift:113)
8  StylightKit2                   0x1010e3f00 specialized thunk (StylightKit.swift:42)
9  RealmSwift                     0x100a2f07c thunk (Migration.swift)
10 RealmSwift                     0x100a2f07c thunk (Migration.swift)
11 Realm                          0x100d777d0 -[RLMMigration execute:] (RLMMigration.mm:111)
12 Realm                          0x100debe08 std::__1::__function::__func<+[RLMRealm realmWithConfiguration:error:]::$_0, std::__1::allocator<+[RLMRealm realmWithConfiguration:error:]::$_0>, void (std::__1::shared_ptr<realm::Realm>, std::__1::shared_ptr<realm::Realm>)>::operator()(std::__1::shared_ptr<realm::Realm>&&, std::__1::shared_ptr<realm::Realm>&&) (RLMRealm.mm:313)
13 Realm                          0x100dfaf98 std::__1::__function::__func<realm::Realm::update_schema(std::__1::unique_ptr<realm::Schema, std::__1::default_delete<realm::Schema> >, unsigned long long)::$_0, std::__1::allocator<realm::Realm::update_schema(std::__1::unique_ptr<realm::Schema, std::__1::default_delete<realm::Schema> >, unsigned long long)::$_0>, void (realm::Group*, realm::Schema&)>::operator()(realm::Group*&&, realm::Schema&) (shared_realm.cpp:272)
14 Realm                          0x100d3ee40 std::__1::function<void (realm::Group*, realm::Schema&)>::operator()(realm::Group*, realm::Schema&) const (functional:1817)
15 Realm                          0x100d4ed50 realm::ObjectStore::update_realm_with_schema(realm::Group*, realm::Schema const&, unsigned long long, realm::Schema&, std::__1::function<void (realm::Group*, realm::Schema&)>) (vector:441)
16 Realm                          0x100df9e00 realm::Realm::update_schema(std::__1::unique_ptr<realm::Schema, std::__1::default_delete<realm::Schema> >, unsigned long long) (functional:1766)
17 Realm                          0x100de96a8 +[RLMRealm realmWithConfiguration:error:] (memory:2712)
18 RealmSwift                     0x100a3f910 Realm.__allocating_init() throws -> Realm (Realm.swift)
19 StylightKit2                   0x101121374 static OverviewPost.(get(input : OverviewPost.InputParameters) -> Promise<Output<Int>, Request>).(closure #2).(closure #1) (OverviewPost.swift:84)
20 Alamofire                      0x1013a0974 partial apply for thunk (ResponseSerialization.swift)
21 Alamofire                      0x1013a35f0 specialized Request.(response<A where ...> (queue : OS_dispatch_queue?, responseSerializer : A, completionHandler : (Response<A.SerializedObject, A.ErrorObject>) -> ()) -> Self).(closure #1).(closure #1) (ResponseSerialization.swift)
22 libdispatch.dylib              0x18091d4bc _dispatch_call_block_and_release
23 libdispatch.dylib              0x18091d47c _dispatch_client_callout
24 libdispatch.dylib              0x180922b84 _dispatch_main_queue_callback_4CF
25 CoreFoundation                 0x180e88d50 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__
26 CoreFoundation                 0x180e86bb8 __CFRunLoopRun
27 CoreFoundation                 0x180db0c50 CFRunLoopRunSpecific
28 GraphicsServices               0x182698088 GSEventRunModal
29 UIKit                          0x18609a088 UIApplicationMain
30 Stylight                       0x1000f2fd8 main (main.swift:12)
31 libdispatch.dylib              0x18094e8b8 (Missing)

Version of Realm and Tooling

Realm version: v1.0.0

Xcode version: 7.3.1

Dependency manager: carthage

@mrackwitz mrackwitz self-assigned this Jun 13, 2016
@mrackwitz
Copy link
Contributor

Hey Bernhard, sorry that I didn't got back to you earlier, missed that you filed an issue over here.

Usually this should work without any problems, just bump the schemaVersion and add an empty migration block.
Here was the first hurdle we had to add a migration since it was crashing. So we added the following migration.

That's true. How was it crashing for you? How were you testing the migration?


Coming to the problem you're seeing with the deployed version: Did you added dateSaved as a property and users could be stuck on an older version which don't have that property yet in their schemas? Because in such a case you would get that error on an attempt to access a non-existing property.

So if you still know or can figure out with which version, you introduced that property, then you can just make sure that this migration enumerations only objects of schemas which have this property already.

if (5...13).contains(oldSchemaVersion) {
  migration.enumerate(Post.className()) { oldObject, newObject in
    if let oldDateSaved = oldObject?["dateSaved"] as? NSDate {
       newObject?["dateSaved"] = oldDateSaved.timeIntervalSince1970 > 0 ? oldDateSaved : nil
    }
  }
}

Alternatively you can dynamically check the oldObject.objectSchema to figure out whether that property already exists. This could look then like below:

if oldSchemaVersion < 13 {
  migration.enumerate(Post.className()) { oldObject, newObject in
    guard let _ = oldObject?.objectSchema["dateSaved"] else {
       newObject?["dateSaved"] = nil
       return
    }
    if let oldDateSaved = oldObject?["dateSaved"] as? NSDate {
       newObject?["dateSaved"] = oldDateSaved.timeIntervalSince1970 > 0 ? oldDateSaved : nil
    }
  }
}

@BObereder
Copy link
Author

We test migration with running the tests of our api communication framwork with the old version on the simulator and then run the tests for new new version.
We of course also test it in the app then with updating the app from the old version to the new version.

dateSaved was added more then 1,5 years ago and we also have a migration when we introduced it (never had problems so far)
Just to be sure we changed our migration to this:

if oldSchemaVersion < 14 {
  migration.enumerate(Post.className()) { oldObject, newObject in
    if oldObject?.objectSchema.properties.filter({ $0.name == "dateSaved" }).count != 0 {
      if let oldDateSaved = oldObject?["dateSaved"] as? NSDate {
        newObject?["dateSaved"] = oldDateSaved.timeIntervalSince1970 > 0 ? oldDateSaved : nil
      }
    }
  }
}

We do not see any crashes right now but it looks like we are stuck in migration somewhere.
Isn't there a way to delete the realm if the migration goes wrong or something like this?

@mrackwitz
Copy link
Contributor

We do not see any crashes right now but it looks like we are stuck in migration somewhere.

Could you elaborate what you mean by the latter part?

Isn't there a way to delete the realm if the migration goes wrong or something like this?

There is deleteRealmIfMigrationNeeded, which you can use e.g. if you only store cached data in the Realm and don't want to care about migrations at all. But it wouldn't run the migration, so it's likely not what you're looking for. As long as you're migrating you shouldn't delete the Realm file as it is open.

Could you reproduce any of the errors you describe locally? If so, you're more than welcome to share more info.

@jpsim
Copy link
Contributor

jpsim commented Jun 23, 2016

@BObereder hi, just following up on @mrackwitz's last comment. We'd love to help.

@jpsim
Copy link
Contributor

jpsim commented Jun 30, 2016

Closing since we haven't heard back from @BObereder in a while.

@jpsim jpsim closed this as completed Jun 30, 2016
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 16, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

4 participants