realm-swift icon indicating copy to clipboard operation
realm-swift copied to clipboard

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

Open HovhannesPoghosyan opened this issue 4 years ago • 28 comments

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: ...

HovhannesPoghosyan avatar Sep 13 '21 20:09 HovhannesPoghosyan

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

jsflax avatar Sep 13 '21 20:09 jsflax

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<A>(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
}

}

HovhannesPoghosyan avatar Sep 13 '21 20:09 HovhannesPoghosyan

@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.

leemaguire avatar Oct 04 '21 11:10 leemaguire

@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() } } }

HovhannesPoghosyan avatar Oct 05 '21 11:10 HovhannesPoghosyan

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
    }
}

leemaguire avatar Oct 05 '21 12:10 leemaguire

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

HovhannesPoghosyan avatar Oct 06 '21 07:10 HovhannesPoghosyan

Hi @HovhannesPoghosyan did you manage to solve your issue?

leemaguire avatar Oct 18 '21 10:10 leemaguire

no @leemaguire unfortunately i have not fixed this issue yet

HovhannesPoghosyan avatar Oct 19 '21 13:10 HovhannesPoghosyan

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 ?

Vincentzzg avatar Dec 02 '21 06:12 Vincentzzg

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''

mcorkidi avatar Mar 30 '22 20:03 mcorkidi

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.

sipersso avatar Jun 01 '22 07:06 sipersso

Any updates on this? Running into the same issue

LilaQ avatar Aug 06 '22 15:08 LilaQ

Me too, any updates?

Nerkyator avatar Aug 29 '22 08:08 Nerkyator

The same issue

NuclleaR avatar Sep 16 '22 23:09 NuclleaR

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

Vincentzzg avatar Sep 17 '22 04:09 Vincentzzg

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?

matthewmorek avatar Oct 30 '22 16:10 matthewmorek

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 avatar Nov 01 '22 11:11 leemaguire

@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 avatar Nov 01 '22 12:11 leemaguire

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

matthewmorek avatar Nov 01 '22 13:11 matthewmorek

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

chrisrohrer avatar Nov 15 '22 16:11 chrisrohrer

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

nybohansen avatar Dec 18 '22 07:12 nybohansen

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.

lilingxi01 avatar Jan 17 '23 20:01 lilingxi01

@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.

westland42 avatar Feb 08 '23 15:02 westland42

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

aejimmi avatar Feb 22 '23 11:02 aejimmi

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!

stromyc avatar Feb 22 '23 15:02 stromyc

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!

apederson94 avatar Mar 07 '23 06:03 apederson94

@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?

chrisrohrer avatar Apr 22 '23 06:04 chrisrohrer

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

philipbel avatar Oct 14 '23 18:10 philipbel