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

Can't set object of type 'Skin' to property of type 'Skin' #7435

Open
HovhannesPoghosyan opened this issue Sep 13, 2021 · 28 comments
Open

Can't set object of type 'Skin' to property of type 'Skin' #7435

HovhannesPoghosyan opened this issue Sep 13, 2021 · 28 comments

Comments

@HovhannesPoghosyan
Copy link

How frequently does the bug occur?

Seen once

Description

I have some realm model which has another realm object as a property and i am getting the crash report from firebase , when i am trying to set the value of that property , with this error message "Can't set object of type 'Skin' to property of type 'Skin'"

Stacktrace & log output

No response

Can you reproduce the bug?

Not yet

Reproduction Steps

No response

Version

10.7.2

What SDK flavour are you using?

Local Database only

Are you using encryption?

No, not using encryption

Platform OS and version(s)

iOS 14.7.1

Build environment

Xcode version: ...
Dependency manager and version: ...

@jsflax
Copy link
Contributor

jsflax commented Sep 13, 2021

Can you provide us a code sample and stack trace please?

@HovhannesPoghosyan
Copy link
Author

HovhannesPoghosyan commented Sep 13, 2021

HI @jsflax, thank you for your quick response.
Here is the log from firebase

Fatal Exception: RLMException
0 CoreFoundation 0x1a480a708 __exceptionPreprocess
1 libobjc.A.dylib 0x1b93147a8 objc_exception_throw
2 Realm 0x103e3d00c invocation function for block in objc_object* (anonymous namespace)::makeSetter<RLMObjectBase* __strong, RLMObjectBase* __strong>(RLMProperty*) + 145 (RLMAccessor.mm:145)
3 madrid 0x1009aa8f4 VideoSettings.setSkin(:) + 82 (VideoSettings.swift:82)
4 madrid 0x100b5b5c0 specialized VideoSettingsSetScheme.pull(
:) (VideoSettingsScheme.swift)
5 madrid 0x100a4a014 ProjectSettings.setDisplaySettings(:) + 127 (ProjectSettings.swift:127)
6 madrid 0x100b59d90 Project.setSettings(
:) (Project.swift)
7 madrid 0x1008b0d98 specialized ProjectSetScheme.pull(:) (ProjectScheme.swift)
8 madrid 0x1008af3e8 (Missing)
9 madrid 0x1009dcea8 closure #1 in Realm.updateProperty(completion:) + 25 (RealmExtension.swift:25)
10 madrid 0x100adee84 thunk for @callee_guaranteed () -> (@error @owned Error) ()
11 madrid 0x1008b3b7c partial apply for thunk for @callee_guaranteed () -> (@error @owned Error) ()
12 madrid 0x1008b3d60 thunk for @callee_guaranteed () -> (@error @owned Error)partial apply
13 RealmSwift 0x1044cc110 Realm.write(withoutNotifying:
:) + 255 (Realm.swift:255)
14 madrid 0x1008af2a4 ProjectDataProvider.pushNewObjectsToLocalDatabase(:realm:organizationId:) (ProjectDataProvider.swift)
15 madrid 0x1009ac990 closure #1 in GetProjectsSuccessReader.read(
:) (ModifiedDataDataProvider.swift)
16 madrid 0x100988958 thunk for @escaping @callee_guaranteed () -> () ()
17 libdispatch.dylib 0x1a43f5a84 _dispatch_call_block_and_release
18 libdispatch.dylib 0x1a43f781c _dispatch_client_callout
19 libdispatch.dylib 0x1a440910c _dispatch_root_queue_drain
20 libdispatch.dylib 0x1a44097d8 _dispatch_worker_thread2
21 libsystem_pthread.dylib 0x1f0596768 _pthread_wqthread
22 libsystem_pthread.dylib 0x1f059d74c start_wqthread

here is my class where i got the crash, it is in the setSkin function

class VideoSettings: BaseRealmObject, VideoSettingsScheme {

@objc dynamic private var showSkin: Bool = true
@objc dynamic private var showTagInformation: Bool = true
@objc dynamic private var showTagComments: Bool = true
@objc dynamic private var showAnimation: Bool = true
@objc dynamic private var skinSize: Int = 3
@objc dynamic private var skinPosition: Int = 2
@objc dynamic private var skin: Skin?
@objc dynamic private var tagCommentTiming: Int = 2

private let animations = List<Animation>()

func setShowSkin(_ showSkin: Bool) {
    self.showSkin = showSkin
}

func getShowSkin() -> Bool {
    return showSkin
}

func setShowTagInformation(_ showTagInformation: Bool) {
    self.showTagInformation = showTagInformation
}

func getShowTagInformation() -> Bool {
    return showTagInformation
}

func setShowTagComments(_ showTagComments: Bool) {
    self.showTagComments = showTagComments
}

func getShowTagComments() -> Bool {
    return showTagComments
}

func setShowAnimation(_ showAnimation: Bool) {
    self.showAnimation = showAnimation
}

func getShowAnimation() -> Bool {
    return showAnimation
}

func setSkinSize(_ skinSize: Int) {
    self.skinSize = skinSize
}

func getSkinSize() -> Int {
    return skinSize
}

func setSkinPosition(_ skinPosition: Int) {
    self.skinPosition = skinPosition
}

func getSkinPosition() -> Int {
    return skinPosition
}

func setSkin(_ skin: SkinUi) {
    let newSkin = Skin(skin.getId()).pull(skin)
    let realm = LocalDatabaseManager.instance.getSafeRealm()
    if realm.isInWriteTransaction {
        realm.add(newSkin, update: .modified)
    } else {
        realm.updateProperty {
            realm.add(newSkin, update: .modified)
        }
    }
    self.skin = newSkin
}

func getSkin() -> SkinUi {
    if let skin = skin {
        return SkinUi(skin.getId()).pull(skin)
    } else {
        return SkinUi()
    }
}

func setAnimations(_ animations: [AnimationUi]) {
    self.animations.removeAll()
    let realm = LocalDatabaseManager.instance.getSafeRealm()
    let newAnimations = animations.map({ Animation($0.getId()).pull($0) })
    
    if realm.isInWriteTransaction {
        realm.add(newAnimations, update: .modified)
    } else {
        realm.updateProperty {
            realm.add(newAnimations, update: .modified)
        }
    }
    self.animations.append(objectsIn: newAnimations)
}

func getAnimations() -> [AnimationUi] {
    return animations.map({ AnimationUi($0.getId()).pull($0) })
}

func setTagCommentTiming(_ tagCommentTiming: Int) {
    self.tagCommentTiming = tagCommentTiming
}

func getTagCommentTiming() -> Int {
    return tagCommentTiming
}

}

@jsflax jsflax self-assigned this Sep 14, 2021
@leemaguire
Copy link
Contributor

@HovhannesPoghosyan it would be worth changing the logic inside of setSkin to not check if the realm is already in a write transaction. What does realm.updateProperty look like? unless you are facing issues with multithreading or you are calling beginWrite manually you should never need to implement this logic.

@HovhannesPoghosyan
Copy link
Author

@leemaguire here is my update property, and don't get what logic should i change

import RealmSwift

extension Realm {
func updateProperty(completion: () -> Void) {
try! write { completion() }
}
}

@leemaguire
Copy link
Contributor

Could you try:

func setSkin(_ skin: SkinUi) {
    let newSkin = Skin(skin.getId()).pull(skin)
    // If VideoSettings is already managed you will have access to the realm.
    try! realm.write {
        self.skin = newSkin
    }
}

@HovhannesPoghosyan
Copy link
Author

sorry @leemaguire i don't think that this is the thread issue and realm.write will fix everything

@leemaguire
Copy link
Contributor

Hi @HovhannesPoghosyan did you manage to solve your issue?

@HovhannesPoghosyan
Copy link
Author

no @leemaguire unfortunately i have not fixed this issue yet

@Vincentzzg
Copy link

I also encountered this problem.
I found that this problem is due to the use of objects managed by Realm to set thet property. If the setting is a newly created object that is not managed by Realm, setting the property is successful.

@leemaguire @HovhannesPoghosyan

my log:
2021-12-02 13:53:08.304851+0800 HikIMSdk[4555:6334909] *** Terminating app due to uncaught exception 'RLMException', reason: 'Can't set object of type 'HikMessageRecord' to property of type 'HikMessageRecord''
*** First throw call stack:
(0x1807e90fc 0x199015d64 0x102fd7a80 0x102fb3638 0x102fce8a4 0x100864854 0x1009da514 0x1032148f8 0x103214790 0x103214700 0x1009da3f0 0x100b0d2e4 0x100b0e720 0x18077af88 0x180816c3c 0x1807e9ff4 0x180790df4 0x181f8df68 0x10080d444 0x1008f35cc 0x100905854 0x1008d3740 0x100860a64 0x10205c6d4 0x10205e3b4 0x102060f2c 0x102072500 0x102072f0c 0x1f1a0e0b8 0x1f1a0de94)
libc++abi: terminating with uncaught exception of type NSException
dyld4 config: DYLD_LIBRARY_PATH=/usr/lib/system/introspection DYLD_INSERT_LIBRARIES=/Developer/usr/lib/libBacktraceRecording.dylib:/Developer/usr/lib/libMainThreadChecker.dylib:/Developer/Library/PrivateFrameworks/DTDDISupport.framework/libViewDebuggerSupport.dylib
*** Terminating app due to uncaught exception 'RLMException', reason: 'Can't set object of type 'HikMessageRecord' to property of type 'HikMessageRecord''
terminating with uncaught exception of type NSException

The point of collapse is here:
截屏2021-12-02 下午1 58 14

The type is correct, but the check fails,why ?

@mcorkidi
Copy link

mcorkidi commented Mar 30, 2022

I have same problem. I simplified code for example.
Model:

`
class Order: Object, ObjectKeyIdentifiable {
@objc dynamic var orderID : String = NSUUID().uuidString
@objc dynamic var client : Client? = nil
@objc dynamic var name : String = "No Name"

override static func primaryKey() -> String? {
    return "orderID"
  }

}`

'
class Client: Object, ObjectKeyIdentifiable {

@objc dynamic var account : String = ""
@objc dynamic var name : String = "No Name"

}'

When trying this,

try! realm.write{ currentOrder!.client = client }

This is the error:

*** Terminating app due to uncaught exception 'RLMException', reason: 'Can't set object of type 'Client' to property of type 'Client''

@sipersso
Copy link

sipersso commented Jun 1, 2022

Just ran into the same issue. For me, this had to do with frozen realms. I was trying to use a frozen realm object as a backlink to another object. In order to resolve the issue, I had to thaw() the object first so that it was a live instance.

@LilaQ
Copy link

LilaQ commented Aug 6, 2022

Any updates on this? Running into the same issue

@Nerkyator
Copy link

Me too, any updates?

@NuclleaR
Copy link

The same issue

@Vincentzzg
Copy link

The problem is solved
Do not set objects already managed by Realm

@matthewmorek
Copy link

I'm encountering the same issue but when using @ObservedRealmObject with SwiftUI's Picker.

Here is my code to help reproduce this issue:

import SwiftUI
import RealmSwift

final class Item: Object, ObjectKeyIdentifiable {
    @Persisted(primaryKey: true) var _id: ObjectId
    @Persisted var title: String
    @Persisted var ownerId: String
    @Persisted var category: ItemCategory?
}

final class ItemCategory: Object, ObjectKeyIdentifiable {
    @Persisted(primaryKey: true) var _id: ObjectId
    @Persisted var name: String
    @Persisted var ownerId: String
}

struct ItemDetailsView: View {
    @ObservedRealmObject var item: Item
    @ObservedResults(ItemCategory.self) var categories

    var body: some View {
        Picker("Category", selection: $item.category) {
            Text("None").tag(nil as ItemCategory?)
            ForEach(categories, id: \.self) { category in
                Text(category.name)
                    .tag(Optional(category))
            }
        }
    }
}

I've tried using _id but that means the Picker doesn't set new values, it only displays the categories correctly, and when I use Category object to set as Item.category, it throws the following exception:

*** Terminating app due to uncaught exception 'RLMException', reason: 'Can't set object of type 'ItemCategory' to property of type 'ItemCategory''

Am I using the SwiftUI Picker with Realm wrong?

@leemaguire
Copy link
Contributor

Hi @matthewmorek, Thanks for the reproduction case, the usage of the picker looks correct. I'm investigating what the issue is on our end.

@leemaguire
Copy link
Contributor

@matthewmorek can you try:

var body: some View {
        Picker("Category", selection: $item.category) {
            Text("None").tag(nil as ItemCategory?)
            ForEach(categories, id: \.self) { category in
                Text(category.name)
                    .tag(category.thaw())
            }
        }
    }

as a workaround for now? What's happening is that a frozen Realm object (ItemCategory) is trying to be set to a non-frozen version of Item, and we are not handling that on our end. Doing .tag(category.thaw()) is a temporary workaround which works for me.

@matthewmorek
Copy link

@leemaguire Hey, thanks for this workaround. It works well and I'm happy to use it until this is sorted out at your end! 👍🏻

@chrisrohrer
Copy link

@leemaguire a big thanks from me too, ran into exactly the same issue

@nybohansen
Copy link

@leemaguire a big thanks from me too - I have been struggling with this issue for a whole day, before I came across your workaround.

@lilingxi01
Copy link

I have just met this issue and got resolved myself. My use case is that I want to assign an existing object A to a related property of another existing object B.

try! realm.write {
    existingObjectB.relatedProperty = relatedObjectA
}

Both of them are coming from the database directly, which means that none of them is new.

The solution: thaw both of them before any assignment, and then assign the thawed object A to the thawed object B.

Hope it helps.

@westland42
Copy link

@matthewmorek can you try:

var body: some View {
        Picker("Category", selection: $item.category) {
            Text("None").tag(nil as ItemCategory?)
            ForEach(categories, id: \.self) { category in
                Text(category.name)
                    .tag(category.thaw())
            }
        }
    }

as a workaround for now? What's happening is that a frozen Realm object (ItemCategory) is trying to be set to a non-frozen version of Item, and we are not handling that on our end. Doing .tag(category.thaw()) is a temporary workaround which works for me.

@leemaguire Based on the above message, it sounds like this is a bug in the Realm client code (since you're talking about workarounds). Does MongoDB plan on fixing this soon? Like many others, I got bit by this recently and lost many hours trying to track down a solution. Thanks.

@aejimmi
Copy link

aejimmi commented Feb 22, 2023

I too experienced this and thanks the workout. Does the job

@stromyc
Copy link

stromyc commented Feb 22, 2023

I had the same issue !

Would it not help if the error was more descriptive, like "Can't set frozen object of type"X" to property of type "X".

Leemaguire, thanks for posting a solution!

@apederson94
Copy link

Just ran into the same issue. For me, this had to do with frozen realms. I trying to use a frozen realm object as a backlink to another. In order to resolve the issue, I had to thaw() the object first so that it was a live instance.

@sipersso This comment is a hidden gem 💎! My issue was resolved once I thawed both objects in question. Thank you so much!

@chrisrohrer
Copy link

@matthewmorek can you try:

var body: some View {
        Picker("Category", selection: $item.category) {
            Text("None").tag(nil as ItemCategory?)
            ForEach(categories, id: \.self) { category in
                Text(category.name)
                    .tag(category.thaw())
            }
        }
    }

as a workaround for now? What's happening is that a frozen Realm object (ItemCategory) is trying to be set to a non-frozen version of Item, and we are not handling that on our end. Doing .tag(category.thaw()) is a temporary workaround which works for me.

@leemaguire Based on the above message, it sounds like this is a bug in the Realm client code (since you're talking about workarounds). Does MongoDB plan on fixing this soon? Like many others, I got bit by this recently and lost many hours trying to track down a solution. Thanks.

@leemaguire I am using the workaround in a macOS app, but with many pickers the multiple thaw() turns into a serious performance issue. Any plans to fix this on the Realm side soon?

@sync-by-unito sync-by-unito bot removed the T-Bug label Sep 12, 2023
@philipbel
Copy link

This is very, very annoying, and the error message couldn't be more confusing as to what the issue actually is.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests