Unacceptable type of value for ordered to-many relationship when writing swift case - objective-c

I am working on a project that requires me to add a new test case on an existing file structure. Right now I am doing a test case that needs to do api call to get maintenance information.
The maintenance information I am getting back is structured as follows:
#objc(MaintenanceData)
class MaintenanceData: WebServiceEntity, Persistable {
static var contentId: ContentId = "maintenance"
#NSManaged var version: String
#NSManaged var maintenance: Bool
#NSManaged var maintenanceDescription: String?
#NSManaged var features: [FeatureMaintenanceData]?
public static func fieldMapping() -> [FieldName: String] {
return [
"version": "version",
"maintenance": "maintenance",
"maintenanceDescription": "maintenanceDescription",
"features": "features"
]
}
}
** For security reasons, I changed some code
Right now I have to mock a fake MaintenanceData to test the features property, which is an array of [FeatureMaintenanceData]
The FeatureMaintenanceData is written as follows:
#objc(FeatureMaintenanceData)
class FeatureMaintenanceData: WebServiceEntity, Persistable {
static var contentId: ContentId = "featureMaintenance"
#NSManaged var identifier: String
#NSManaged var maintenance: Bool
#NSManaged var maintenanceDescription: String?
public static func fieldMapping() -> [FieldName: String] {
return [
"identifier": "identifier",
"maintenance": "maintenance",
"maintenanceDescription": "maintenanceDescription"
]
}
}
Right now I need to mock the data, there is a function in the MockDataFactory which returns a MaintenanceData object, I need to make use of it and pass it to the function for testing. The function is written as follows:
#discardableResult func createAndInsertMaintenance(
version: String = "",
maintenance: Bool = false,
maintenanceDescription: String? = nil,
features: [FeatureMaintenanceData]? = nil,
) -> MaintenanceData {
let maintenance = NSEntityDescription.insertNewObject(
forEntityName: String(describing: MaintenanceData.self),
into: managedObjectContext
) as! MaintenanceData
maintenance.version = version
maintenance.softUpdateMinimalVersion = softUpdateMinimalVersion
maintenance.maintenance = maintenance
maintenance.maintenanceDescription = maintenanceDescription
maintenance.features = features <-----This is where error occurs
return updateMaintenance
}
I created and pass the fake FeatureMaintenanceData to the function
let featureMaintenance = NSEntityDescription.insertNewObject(
forEntityName: "FeatureMaintenanceData",
into: managedObjectContext
) as! FeatureMaintenanceData
featureMaintenance.identifier = "Microwave"
featureMaintenance.maintenance = true
featureMaintenance.maintenanceDescription = "test"
It however returns an error Unacceptable type of value for ordered to-many relationship: property = "features"; desired type = NSOrderedSet;
Since I don't know Obj-c, could someone explain to me what is the problem and how to solve it? Much thanks!

Related

How to assign value to NSManaged object in Swift?

I need to write test case and in the test case, I need to mock an object of the following class and put them into an array. e.g. moviesArray = [MovieCoreData]. I am wondering how I can instantiate this?
#objc(MovieCoreData)
class MovieCoreData {
static var genre: Genre = "Comedy"
#NSManaged var actor: String
#NSManaged var released: Bool
#NSManaged var name: String?
public static func mapping() -> [FieldName: String] {
return [
"actor": "actor",
"released": "released",
"name": "name"
]
}
}
For example, I tried to write
moviesArray = [MovieCoreData(actor: "Johnny Depp", released: True, name: "Pirate Captain"]
and
moviesArray.first.actor = "Johnny Depp"
moviesArray.first.released = "true"
moviesArray.first.name = "Pirate Captain"
none of them worked, I admit I don't know much about Objective-C and NSManaged, can someone tell me how to create an array of MovieCoreData with fake data?
The #NSManaged attribute belongs to Core Data.
The class must be a subclass of NSManagedObject and instances must be created with regard to the NSManagedObjectContext to take advantage of its functionality

How can I set the JsName for a property's backing field in Kotlin?

I played about with Kotlin's unsupported JavaScript backend in 1.0.x and am now trying to migrate my toy project to 1.1.x. It's the barest bones of a single-page web app interfacing with PouchDB. To add data to PouchDB you need JavaScript objects with specific properties _id and _rev. They also need to not have any other properties beginning with _ because they're reserved by PouchDB.
Now, if I create a class like this, I can send instances to PouchDB.
class PouchDoc(
var _id: String
) {
var _rev: String? = null
}
However, if I do anything to make the properties virtual -- have them override an interface, or make the class open and create a subclass which overrides them -- the _id field name becomes mangled to something like _id_mmz446$_0 and so PouchDB rejects the object. If I apply #JsName("_id") to the property, that only affects the generated getter and setter -- it still leaves the backing field with a mangled name.
Also, for any virtual properties whose names don't begin with _, PouchDB will accept the object but it only stores the backing fields with their mangled names, not the nicely-named properties.
For now I can work around things by making them not virtual, I think. But I was thinking of sharing interfaces between PouchDoc and non-PouchDoc classes in Kotlin, and it seems I can't do that.
Any idea how I could make this work, or does it need a Kotlin language change?
I think your problem should be covered by https://youtrack.jetbrains.com/issue/KT-8127
Also, I've created some other related issues:
https://youtrack.jetbrains.com/issue/KT-17682
https://youtrack.jetbrains.com/issue/KT-17683
And right now You can use one of next solutions, IMO third is most lightweight.
interface PouchDoc1 {
var id: String
var _id: String
get() = id
set(v) { id = v}
var rev: String?
var _rev: String?
get() = rev
set(v) { rev = v}
}
class Impl1 : PouchDoc1 {
override var id = "id0"
override var rev: String? = "rev0"
}
interface PouchDoc2 {
var id: String
get() = this.asDynamic()["_id"]
set(v) { this.asDynamic()["_id"] = v}
var rev: String?
get() = this.asDynamic()["_rev"]
set(v) { this.asDynamic()["_rev"] = v}
}
class Impl2 : PouchDoc2 {
init {
id = "id1"
rev = "rev1"
}
}
external interface PouchDoc3 { // marker interface
}
var PouchDoc3.id: String
get() = this.asDynamic()["_id"]
set(v) { this.asDynamic()["_id"] = v}
var PouchDoc3.rev: String?
get() = this.asDynamic()["_rev"]
set(v) { this.asDynamic()["_rev"] = v}
class Impl3 : PouchDoc3 {
init {
id = "id1"
rev = "rev1"
}
}
fun keys(a: Any) = js("Object").getOwnPropertyNames(a)
fun printKeys(a: Any) {
println(a::class.simpleName)
println(" instance keys: " + keys(a).toString())
println("__proto__ keys: " + keys(a.asDynamic().__proto__).toString())
println()
}
fun main(args: Array<String>) {
printKeys(Impl1())
printKeys(Impl2())
printKeys(Impl3())
}
I got a good answer from one of the JetBrains guys, Alexey Andreev, over on the JetBrains forum at https://discuss.kotlinlang.org/t/controlling-the-jsname-of-fields-for-pouchdb-interop/2531/. Before I describe that, I'll mention a further failed attempt at refining #bashor's answer.
Property delegates
I thought that #bashor's answer was crying out to use property delegates but I couldn't get that to work without infinite recursion.
class JSMapDelegate<T>(
val jsobject: dynamic
) {
operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
return jsobject[property.name]
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
jsobject[property.name] = value
}
}
external interface PouchDoc4 {
var _id: String
var _rev: String
}
class Impl4() : PouchDoc4 {
override var _id: String by JSMapDelegate<String>(this)
override var _rev: String by JSMapDelegate<String>(this)
constructor(_id: String) : this() {
this._id = _id
}
}
The call within the delegate to jsobject[property.name] = value calls the set function for the property, which calls the delegate again ...
(Also, it turns out you can't put a delegate on a property in an interface, even though you can define a getter/setter pair which work just like a delegate, as #bashor's PouchDoc2 example shows.)
Using an external class
Alexey's answer on the Kotlin forums basically says, "You're mixing the business (with behaviour) and persistence (data only) layers: the right answer would be to explicitly serialise to/from JS but we don't provide that yet; as a workaround, use an external class." The point, I think, is that external classes don't turn into JavaScript which defines property getters/setters, because Kotlin doesn't let you define behaviour for external classes. Given that steer, I got the following to work, which does what I want.
external interface PouchDoc5 {
var _id: String
var _rev: String
}
external class Impl5 : PouchDoc5 {
override var _id: String
override var _rev: String
}
fun <T> create(): T = js("{ return {}; }")
fun Impl5(_id: String): Impl5 {
return create<Impl5>().apply {
this._id = _id
}
}
The output of keys for this is
null
instance keys: _id
__proto__ keys: toSource,toString,toLocaleString,valueOf,watch,unwatch,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,__defineGetter__,__defineSetter__,__lookupGetter__,__lookupSetter__,__proto__,constructor
Creating external classes
Three notes about creating instances of external classes. First, Alexey said to write
fun <T> create(): T = js("{}")
but for me (with Kotlin 1.1) that turns into
function jsobject() {
}
whose return value is undefined. I think this might be a bug, because the official doc recommends the shorter form, too.
Second, you can't do this
fun Impl5(_id: String): Impl5 {
return (js("{}") as Impl5).apply {
this._id = _id
}
}
because that explicitly inserts a type-check for Impl5, which throws ReferenceError: Impl5 is not defined (in Firefox, at least). The generic function approach skips the type-check. I'm guessing that's not a bug, since Alexey recommended it, but it seems odd, so I'll ask him.
Lastly, you can mark create as inline, though you'll need to suppress a warning :-)

Unable to Parse property name "description" in Json file in realm swift

I am trying to parse JSON through realm Swift Here is my Json. response
{
code = 1;
data = {
subjects = (
{
code = 786;
description = "not a good deal";
id = 13;
name = "Mechine Learning in iOS";
}
);
};
message = success;
}
And here it is my swift file to parse this json.
import UIKit
import RealmSwift
import Realm
class Subject: Object
{
#objc dynamic var id: Int = 0
#objc dynamic var code: String!
#objc dynamic var name: String!
#objc dynamic var description: String!
override class func primaryKey() -> String? {
return "id"
}
}
We know that description is keyword in swift, so it shows this error:
Getter for 'description' with Objective-C selector 'description' conflicts with getter for 'description' from superclass 'NSObject' with the same Objective-C selector.
Is there any way to parse description here, without using key value explicitly?
use another parameter for description (myDescription) and override init
import UIKit
import RealmSwift
import Realm
class Subject: Object{
func parseDescription(data : [String: Any]) {
guard let desc:String = data["description"] as? String else{
return
}
myDescription = desc
}
override init(value: Any) {
super.init(value: value)
guard let data: [String: Any] = value as? [String: Any] else {
return
}
parseDescription(data: data)
}
required init(realm: RLMRealm, schema: RLMObjectSchema) {
super.init(realm: realm, schema: schema)
}
required init() {
super.init()
}
required init(value: Any, schema: RLMSchema) {
super.init(value: value, schema: schema)
guard let data: [String: Any] = value as? [String: Any] else {
return
}
parseDescription(data: data)
}
#objc dynamic var id: Int = 0
#objc dynamic var code: String!
#objc dynamic var name: String!
#objc dynamic var myDescription: String!
override class func primaryKey() -> String? {
return "id"
}
}
Found 2 soutions:
Update the date of your machine
Use alternate USB port
To update the datetime of your machine you can open Utilities->Terminal in the installer, check the current datetime with the command date and if it is wrong use the command ntpdate -u time.apple.com
Note that you has to be connected to the internet or use the command date with timestamp to set the datetime manually

Swift extension - Parse Json to NSDictionary Model (By Using Category Like In Obj-C)

I have API request to get json string, something like that:
{
"data":[
{
"id":123,
"name":"Felix"},
{
"id":122,
"name":"Mary"},
{
"id":111,
"name":"Jason"},
]
}
and in my Obj-C NSDictionary+user is
-(NSString *)usrId
{
return self[#"id"];
}
-(NSString *)usrName
{
return self[#"name"];
}
...
and when I use this I import the category class, and access it like dict.name...
I can't find a good answer related to this question. How can I achieve this in Swift?
UPDATED [2017.07.21]
I've chose to use SwiftyJSON library to settle all the json-dictionary-object-mapping works. Save tons of time.
SwiftyJSON
Best and safest way to parse json response to nsdictionary and use it in swift is:
var responseRecord<datastruct> = Array<datastruct>()
struct datastruct
{
var id: String?
var name:String?
init(add: NSDictionary)
{
id = add["id"] as? String
name = add["name"] as? String
}
}
And to access it in program:
print(self.responseRecord.id)
print(self.responseRecord.name)
Simply create a empty Swift class with required properties (Swift 2.2):-
class myClass {
var id:Int?
var name:String?
init(id:Int,name:String)
{
self.id= id
self.name = name
}
}
Then to access in required VC :-
var requiredData:[String]?
var data:[myClass]?
override fun viewDidLoad()
{
super.viewDidLoad()
requiredData = data!.enumerate().map({ (index, category) in
return ("\(category.name!)")
})
print(requiredData)
}
Note: I am assuming you have already populated data in the mentioned "data" variable of myClass type. If not, then you can do so as follows:-
data = [myClass(id:1,name:"aaa"),myClass(id:2,name:"bob"),myClass(id:3,name:"ccc")]

Swift : Parse subclass dynamic var dont get included when retrieving object

I canĀ“t get the object properties when retrieving an object from Parse Data Browser. This happened after I changed from "#NSManaged var friends" to "dynamic var friends". Even "name" show nil in User.logInWithUsernameInBackground block which is crazy because the login succeeds. The ACL for User is set to "public read".
User object:
class User : PFUser, PFSubclassing {
dynamic var friends:[User]!
dynamic var name:String!
override class func load() {
self.registerSubclass()
}
}
Retrieving the User along with the friends. println showing nil
var query = User.query()
query.includeKey("friends")
query.getObjectInBackgroundWithId(currentUser.objectId) {
(pfObject: PFObject!, error: NSError!) -> Void in
if pfObject != nil {
var user = pfObject as User
var friends = user.friends as [User]
println("friends: \(friends)") //nil
} else {
println(error)
}
}
Login. println showing nil
User.logInWithUsernameInBackground(USERNAME, password:PASSWORD) {
(user: PFUser!, error: NSError!) -> Void in
if user != nil {
println("Logged in with user: \(user.name)") //nil
} else {
println(error)
}
}
Looking a little deeper for you, it seems the hurdle is a misunderstanding of what the dynamic modifier in Swift does. Apparently, dynamic in Swift is used for Key-Value observing, not declaring a variable's accessors to be defined at runtime (what #dynamic does in Objective-C)
See this for a description of dynamic in Swift https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/AdoptingCocoaDesignPatterns.html#//apple_ref/doc/uid/TP40014216-CH7-XID_8
and this for the description of why #NSManaged works the way #dynamic does in Objective-C
https://developer.apple.com/library/prerelease/mac/documentation/Swift/Conceptual/BuildingCocoaApps/WritingSwiftClassesWithObjective-CBehavior.html#//apple_ref/doc/uid/TP40014216-CH5-XID_66
With xCode 6.1.1 I was able to get this working without the bridging header but I did need to use #NSManaged. Here's how... Just:
import Parse
at the top of the calling module. For the class declaration .swift file dynamic didn't work so I needed to use #NSManaged for the variable types to get them to link to the Parse class variables successfully. Like this:
class PSCategory : PFObject, PFSubclassing {
override class func load() {
self.registerSubclass()
}
class func parseClassName() -> String! {
return "Category"
}
#NSManaged var Name: String
}
Then in my query all the names are dynamically linked:
var query = PSCategory.query() // PFQuery(className: "Category")
query.cachePolicy = kPFCachePolicyCacheElseNetwork // kPFCachePolicyNetworkElseCache
query.maxCacheAge = 60 * 60 * 24 // One day, in seconds.
query.findObjectsInBackgroundWithBlock {
(categories: [AnyObject]!, error: NSError!) -> Void in
if error == nil {
for abstractCategory in categories {
let category = abstractCategory as PSCategory
NSLog("Category Name: %#", category.Name)
}
} else {
NSLog("Unable to retrieve categories from local cache or network")
}
}