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

Reassignment of mapped properties during json export. #762

Closed
mathieutozer opened this issue Feb 25, 2017 · 2 comments
Closed

Reassignment of mapped properties during json export. #762

mathieutozer opened this issue Feb 25, 2017 · 2 comments

Comments

@mathieutozer
Copy link

mathieutozer commented Feb 25, 2017

I have a model which represents a tree of nodes

The mapping function looks like this

dynamic var subnodes = [Node]()
...
  func mapping(map: Map) {
    // other properties....
    subnodes <- map["subnodes"]
  }

When I get this json string like this:
let json = goalDocument?.toJSONString(prettyPrint: true)

Object mapper reassigns the array to the object at the subnodes <- map["subnodes"] line, triggering KVO which causes a lot of work to be done elsewhere (NSTreeController / NSOutlineView).

Is there a way to avoid this assignment happening? It doesn't seem to be necessary?

Here's the stack trace through the KVO notification from the JSONString query.

#0	0x0000000100087693 in NodeDataSource.outlineViewItemDidExpand(Notification) -> () at /Users/mtozer/code/mycode/Apps/Sword/Sword/NodeDataSource.swift:113
#1	0x0000000100087c17 in @objc NodeDataSource.outlineViewItemDidExpand(Notification) -> () ()
#2	0x00007fff772b7a6c in __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ ()
#3	0x00007fff772b796b in _CFXRegistrationPost ()
#4	0x00007fff772b76d2 in ___CFXNotificationPost_block_invoke ()
#5	0x00007fff77274d63 in -[_CFXNotificationRegistrar find:object:observer:enumerator:] ()
#6	0x00007fff77273d9c in _CFXNotificationPost ()
#7	0x00007fff78c9aa37 in -[NSNotificationCenter postNotificationName:object:userInfo:] ()
#8	0x00007fff74fb5666 in -[NSOutlineView _postItemDidExpandNotification:] ()
#9	0x00007fff74edcff7 in -[NSOutlineView _expandItemEntry:expandChildren:startLevel:] ()
#10	0x00007fff7510a813 in -[NSOutlineView reloadItem:reloadChildren:] ()
#11	0x00007fff7548f51b in -[NSOutlineViewBinder _childrenChangedForNode:] ()
#12	0x00007fff750bc82b in -[NSOutlineViewBinder observeValueForKeyPath:ofObject:change:context:] ()
#13	0x00007fff78cd771d in NSKeyValueNotifyObserver ()
#14	0x00007fff78cd6fb4 in NSKeyValueDidChange ()
#15	0x00007fff78ca5e96 in -[NSObject(NSKeyValueObserverNotification) didChangeValueForKey:] ()
#16	0x00007fff750ba4a9 in -[NSTreeControllerTreeNode updateChildNodesForKeyPath:affectedIndexPaths:] ()
#17	0x00007fff757152eb in -[NSTreeControllerTreeNode observeValueForKeyPath:ofObject:change:context:] ()
#18	0x00007fff78cd771d in NSKeyValueNotifyObserver ()
#19	0x00007fff78cd6fb4 in NSKeyValueDidChange ()
#20	0x00007fff78e15c37 in -[NSObject(NSKeyValueObservingPrivate) _changeValueForKeys:count:maybeOldValuesDict:usingBlock:] ()
#21	0x00007fff78c9ad1d in -[NSObject(NSKeyValueObservingPrivate) _changeValueForKey:key:key:usingBlock:] ()
#22	0x00007fff78d0359b in _NSSetObjectValueAndNotify ()
#23	0x0000000100031b84 in Node.mapping(map : Map) -> () at /Users/mtozer/code/mycode/Apps/Sword/Sword/Goals.swift:325
#24	0x00000001000324f4 in protocol witness for BaseMappable.mapping(map : Map) -> () in conformance Node ()
#25	0x0000000100687848 in Mapper.toJSON(A) -> [String : Any] at /Users/mtozer/code/mycode/Apps/Sword/Pods/ObjectMapper/Sources/Mapper.swift:278
#26	0x0000000100687a94 in Mapper.(toJSONArray([A]) -> [[String : Any]]).(closure #1) at /Users/mtozer/code/mycode/Apps/Sword/Pods/ObjectMapper/Sources/Mapper.swift:286
#27	0x0000000100687b12 in thunk ()
#28	0x0000000100687c2c in partial apply for thunk ()
#29	0x00000001007d7ad6 in Collection.map<A> ((A.Iterator.Element) throws -> A1) throws -> [A1] ()
#30	0x00000001006879fb in Mapper.toJSONArray([A]) -> [[String : Any]] at /Users/mtozer/code/mycode/Apps/Sword/Pods/ObjectMapper/Sources/Mapper.swift:287
#31	0x0000000100692bf4 in static ToJSON.objectArray<A where ...> ([A], map : Map) -> () at /Users/mtozer/code/mycode/Apps/Sword/Pods/ObjectMapper/Sources/ToJSON.swift:118
#32	0x000000010068e98a in >>> infix<A where ...> ([A], Map) -> () at /Users/mtozer/code/mycode/Apps/Sword/Pods/ObjectMapper/Sources/Operators.swift:248
#33	0x000000010068e8f1 in <- infix<A where ...> (inout [A], Map) -> () at /Users/mtozer/code/mycode/Apps/Sword/Pods/ObjectMapper/Sources/Operators.swift:241
#34	0x0000000100031b44 in Node.mapping(map : Map) -> () at /Users/mtozer/code/mycode/Apps/Sword/Sword/Goals.swift:325
#35	0x00000001000324f4 in protocol witness for BaseMappable.mapping(map : Map) -> () in conformance Node ()
#36	0x0000000100687848 in Mapper.toJSON(A) -> [String : Any] at /Users/mtozer/code/mycode/Apps/Sword/Pods/ObjectMapper/Sources/Mapper.swift:278
#37	0x00000001006926af in static ToJSON.object<A where ...> (A, map : Map) -> () at /Users/mtozer/code/mycode/Apps/Sword/Pods/ObjectMapper/Sources/ToJSON.swift:106
#38	0x0000000100692a29 in static ToJSON.optionalObject<A where ...> (A?, map : Map) -> () at /Users/mtozer/code/mycode/Apps/Sword/Pods/ObjectMapper/Sources/ToJSON.swift:113
#39	0x000000010068db2d in >>> infix<A where ...> (A?, Map) -> () at /Users/mtozer/code/mycode/Apps/Sword/Pods/ObjectMapper/Sources/Operators.swift:122
#40	0x000000010068d990 in <- infix<A where ...> (inout A?, Map) -> () at /Users/mtozer/code/mycode/Apps/Sword/Pods/ObjectMapper/Sources/Operators.swift:115
#41	0x0000000100029f55 in GoalDocument.mapping(map : Map) -> () at /Users/mtozer/code/mycode/Apps/Sword/Sword/Goals.swift:81
#42	0x000000010002a934 in protocol witness for BaseMappable.mapping(map : Map) -> () in conformance GoalDocument ()
#43	0x0000000100687848 in Mapper.toJSON(A) -> [String : Any] at /Users/mtozer/code/mycode/Apps/Sword/Pods/ObjectMapper/Sources/Mapper.swift:278
#44	0x0000000100689c25 in Mapper.toJSONString(A, prettyPrint : Bool) -> String? at /Users/mtozer/code/mycode/Apps/Sword/Pods/ObjectMapper/Sources/Mapper.swift:308
#45	0x000000010067fd05 in BaseMappable.toJSONString(prettyPrint : Bool) -> String? at /Users/mtozer/code/mycode/Apps/Sword/Pods/ObjectMapper/Sources/Mappable.swift:76
#46	0x0000000100014ef1 in Document.data(ofType : String) throws -> Data at /Users/mtozer/code/mycode/Apps/Sword/Sword/Document.swift:119
#47	0x00000001000152cb in @objc Document.data(ofType : String) throws -> Data ()
#48	0x00007fff75181950 in -[NSDocument writeToURL:ofType:error:] ()

@tristanhimmelman
Copy link
Owner

subnodes is not reassigned in the toJSON process. I believe, the issue that you are experiencing arises because the <- operator uses the inout flag for the left hand parameter. This is necessary when mapping from JSON to model.

So when toJSONString is called, KVO assumes that subnodes is modified due to the inout flag.

One solution which is not that elegant that should solve your issue is the following:

if map.mappingType == .toJSON {
  subnodes >>> map["subnodes"]
} else if map.mappingType == .fromJSON {
  subnodes <- map["subnodes"]
}

The >>> is used only for generating JSON and does not use the inout flag.

Hope this helps.

@mathieutozer
Copy link
Author

Worked! Thank you!

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

No branches or pull requests

2 participants