I created a Core Data object as follows:
#objc(Gates)
public class Gates : NSManagedObject {
public class func getFetchRequest() -> NSFetchRequest<Gates> {
let request = NSFetchRequest<Gates>(entityName: "Gates")
request.returnsObjectsAsFaults = false
return request
}
#NSManaged var updatedAt: String
#NSManaged var objectId: String
#NSManaged var identifier: String
#NSManaged var name: String
#NSManaged var address: String
#NSManaged var dueDate: String
#NSManaged var productionCode: String
#NSManaged var locationCountry: String
#NSManaged var locationCity: String
#NSManaged var locationBuilding: String
#NSManaged var locationLevel: String
#NSManaged var locationRoom: String
#NSManaged var locationRange: String
#NSManaged var isFavorite: Bool
public func setGateData(gateDict: [String: Any]) {
updatedAt = gateDict["updatedAt"] as? String ?? ""
objectId = gateDict["objectId"] as? String ?? ""
identifier = gateDict["identifier"] as? String ?? ""
name = gateDict["name"] as? String ?? ""
isFavorite = gateDict["isFavorite"] as? Bool ?? false
address = gateDict["address"] as? String ?? ""
dueDate = gateDict["dueDate"] as? String ?? ""
productionCode = gateDict["productionCode"] as? String ?? ""
locationCountry = gateDict["locationCountry"] as? String ?? ""
locationCity = gateDict["locationCity"] as? String ?? ""
locationBuilding = gateDict["locationBuilding"] as? String ?? ""
locationLevel = gateDict["locationLevel"] as? String ?? ""
locationRoom = gateDict["locationRoom"] as? String ?? ""
locationRange = gateDict["locationRange"] as? String ?? ""
}
}
I also set this up in the xcdatamodeld:
Now, after I have saved the object in core data and I'm using the getFetchRequest() method that is part of the class which sets
request.returnsObjectsAsFaults = false on the request but I still getting the following result when I try to print the fetched objects:
<Gates: 0x60c0000959a0> (entity: Gates; id: 0xd000000005e40000 <x-
coredata://B9C33A5D-BF96-433A-9186-F51AA253F488/Gates/p377> ; data: <fault>)
As you can see in this case the data is still data: <fault>.
Why is the object parameters are not retrieved even though I set request.returnsObjectsAsFaults = false? What am I missing?
I'm having this issue and I found in my case instead of using the objects value in line, I initialize a variable with it first and then use that variable.
I would love to know if this is a Core Data bug or if I'm doing something wrong.
public class Person: NSManagedObject, Identifiable {
#NSManaged public var firstName: String
#NSManaged public var lastName: String
#NSManaged public var emailAddress: String
}
This does not work all the time:
CoreDataManager.shared.persistentContainer.performBackgroundTask{ context in
context.automaticallyMergesChangesFromParent = true
context.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
do {
let email = "123Tester#gmail.com"
let request = Person.getPersonWith(email: email)
request.returnsObjectsAsFaults = false //DOES NOT WORK
if let person = try context.fetch(request).first{
print(person.fullName)
}
} catch{
fatalError()
}
}
However this does
CoreDataManager.shared.persistentContainer.performBackgroundTask{ context in
context.automaticallyMergesChangesFromParent = true
context.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
do {
let email = "123Tester#gmail.com"
let request = Person.getPersonWith(email: email)
if let person = try context.fetch(request).first{
let fullName = person.fullName
print(fullName)
}
} catch{
fatalError()
}
}
Related
I have a model which uses init with JSON, so that i can create objects directly from an API response.
However in this instance I want to init the model and manually enter its properties, hence it wont be JSON.
How can i have another init method that allows me to not use the standard JSON method and instead manually enter my params?
The model looks like this...
class Conversation: NSObject {
var id: String
var index: String
var image: String
var firstname: String
var lastname: String
var withuserid: String
var badgeCount: String
init?(_ json: JSON) {
guard let id = json["id"].string,
let index = json["index"].string,
let image = json["image"].string,
let firstname = json["firstname"].string,
let lastname = json["lastname"].string,
let withuserid = json["withuserid"].string,
let badgeCount = json["badgeCount"].string
else { return nil }
self.id = id
self.index = index
self.image = image
self.firstname = firstname
self.lastname = lastname
self.withuserid = withuserid
self.badgeCount = badgeCount
}
}
Just add another init since you can several ones for a struct and class Then just call the desired one:
class Conversation: NSObject {
var id: String
var index: String
var image: String
var firstname: String
var lastname: String
var withuserid: String
var badgeCount: String
init?(_ json: JSON) {
guard let id = json["id"].string,
let index = json["index"].string,
let image = json["image"].string,
let firstname = json["firstname"].string,
let lastname = json["lastname"].string,
let withuserid = json["withuserid"].string,
let badgeCount = json["badgeCount"].string
else { return nil }
self.id = id
self.index = index
self.image = image
self.firstname = firstname
self.lastname = lastname
self.withuserid = withuserid
self.badgeCount = badgeCount
}
init(id: String, index: String, image: String, firstName: String, lastName: String, withUserId: String, badgeCount: String) {
self.id = id
self.index = index
self.image = image
self.firstName = firstName
self.lastName = lastName
self.withUserId = withUserId
self.badgeCount = badgeCount
}
}
A single class or struct can have several designated initializers in Swift.
Then you can call the non-JSON init method like this:
let conv = Conversation(id: "asbe", index: "1", "image: "img", firstName: "John", lastName: "Smith", withUserId: "21", badgeCount: "5"
class Conversation {
var id: String
var index: String
var image: String
var firstName: String
var lastName: String
var withUserId: String
var badgeCount: String
init(id: String, index: String, image: String, firstName: String, lastName: String, withUserId: String, badgeCount: String){
self.id = id
self.index = index
self.image = image
self.firstName = firstName
self.lastName = lastName
self.withUserId = withUserId
self.badgeCount = badgeCount
}
init?(_ json: JSON) {
guard let id = json["id"].string,
let index = json["index"].string,
let image = json["image"].string,
let firstname = json["firstname"].string,
let lastname = json["lastname"].string,
let withuserid = json["withuserid"].string,
let badgeCount = json["badgeCount"].string
else { return nil }
self.id = id
self.index = index
self.image = image
self.firstname = firstname
self.lastname = lastname
self.withuserid = withuserid
self.badgeCount = badgeCount
}
}
Some general advice: I don't see any reason for the class to inherit from NSObject. Swift classes don't need to inherit from any class, so unless you explicitly need a method from another class, don't make your custom classes inherit from others for no reason.
Please make sure you conform to the Swift naming convention, which is lower-camelCase for variable names. I would also rethink the types of some of the variables, without more context, it seems to me, some of them should be of type Int instead of String.
How can make model class for this json data
{
total: 41,
totalPages: 4,
valueData: [
{
id: "23",
lastLogin: "0-Jul-2011 11:27:36 AM",
name: "varii"
},
{
id: "24",
lastLogin: "0-Jul-2015 11:27:36 AM",
name: "sarii"
},
{
id: "25",
lastLogin: "0-Jul-2018 11:27:36 AM",
name: "narii"
} ]
}
class OnResponse {
var total: Int?
var totalPages: Int?
init(response: [String: Any]) {
self.total = response["total"]
self.totalPages = response["totalPages"]
}
}
It's not working how can make it ready for work
and how to pass values to controller to model and how to get value from model
Follow the below class structure
class Response {
var total: Int?
var totalPages: Int?
var valueData: [LoginData]?
init(response: [String: Any]) {
self.total = response["total"]
self.totalPages = response["totalPages"]
var items:[LoginData] = ()
for (data in response["valueData"]) {
let login = LoginData(name: data["name"], lastLogin: data["lastLogin"])
items.append(login)
}
self.valueData = items
}
}
class LoginData {
var name: String?
var lastLogin: String?
init(name: String, lastLogin: String) {
self.name = name
self.lastLogin = lastLogin
}
}
you should use "reverseMatches" to retrieve the array, not the "data". May be you can use a third library to convert your json data to a model, such as Unbox, https://github.com/JohnSundell/Unbox.
Model for Your response :
struct ModelName {
var total: Int?
var totalPage: Int?
var reverseMatches: [LoginDetails]?
}
struct LoginDetails {
var id: String?
var lastLogin: String?
var name: String?
}
Parse the api response and assign the values on the appropriate fields. I have made, all the variables are optional.
Assign values like below.
var obj = Model()
obj.total = response["total"] as? Int
obj should be var, because you are going to mutate the struct values. because struct is value based, not reference based
class DataModel{
var total : Int?
var totalPages : Int?
var valueData : [UserModel]?
init(JSON: [String:Any?]){
self = parser.doParse(JSON: JSON)
}
}
class UserModel{
var id : String?
var lastLogin : String?
var name : String?
}
class parser : NSObject{
class func doParse(JSON: [String:Any?])->DataModel{
let dataModel = DataModel()
dataModel.total = JSON["total"] as? Int
dataModel.totalPages = JSON["totalPages"] as? Int
var userInfo : [UserModel] = []
let valueData : [String:String?]? = JSON["valueData"] as? [String:String?]
if let valueData = valueData{
for dataDict : [String:String?] in valueData{
let itemModel = UserModel()
itemModel.id = dataDict["id"] as? String
itemModel.lastLogin = dataDict["lastLogin"] as? String
itemModel.name = dataDict["name"] as? String
userInfo.append(itemModel)
}
dataModel.valueData = userInfo
}
return dataModel
}
}
class LoginData: NSObject {
let total: Int = 0
let totalPages: Int = 0
let valueData: Array<ValueData> = Array<ValueData>()
override init(total: Int!, totalPages: Int, valueData: Array<ValueData>!) {
self.total = total
self.totalPages = totalPages
self.valueData = valueData
}
}
struct ValueData {
let id: int?
let lastLogin: String?
let name: String?
init(id: int!, lastLogin: string, name: string!)
self.id = id ?? 0
self.lastLogin = lastLogin ?? ""
self.name = name ?? ""
}
}
you should use struct instead of class for creating model object...
advantages of struct over class refer
Why Choose Struct Over Class?
class/24232845
use two struct for holding your data one is for your single total count
and other is for last login detail
struct lastLogin {
let totalCount: (total: Int, totalPages: Int)
let valueArray: [lastLoginDetail]
}
struct lastLoginDetail {
let valueData: (id: String, lastLogin: String,name: String)
}
extension lastLoginDetail {
init(json: [String : String]) throws {
let id = json["id"]
let lastLogin = json["lastLogin"]
let name = json["name"]
let value = (id,lastLogin,name)
self.valueData = value as! (id: String, lastLogin: String, name: String)
}
}
extension lastLogin {
init(json: [String : Any]) throws {
let total = (json["total"] as! NSNumber).intValue
let totalPages = (json["totalPages"] as! NSNumber).intValue
let totalCounts = (total,totalPages)
var userInfo : [lastLoginDetail] = []
// Extract and validate valueData
let valueData = json["valueData"] as? NSArray
if let valueData = valueData{
for dataDict in valueData{
let dic : [String : String] = dataDict as! [String : String]
let lastLoginDeatails = try! lastLoginDetail(json: dic)
userInfo.append(lastLoginDeatails)
}
}
self.valueArray = userInfo
self.totalCount = totalCounts
}
}
func HowToUseModelClass(){
let jsonDic = NSDictionary()
// jsonDic // your json value
let dataValue = try! lastLogin(json: (jsonDic as! [String : Any])) // parsing the data
print(dataValue.totalCount.total)
print(dataValue.totalCount.totalPages)
print(dataValue.valueArray[0].valueData.id)
}
I'm working with web app. I have UITableViewController which deals with NSFetchedResultsController. I store tableView's objects through CoreData. When a user refreshes UI I perform server request and then call batch update for each new entity, my CoreData class looks like:
extension DBOrder {
#NSManaged var comment: String
#NSManaged var date: NSNumber
#NSManaged var id: NSNumber
#NSManaged var maturity_date: NSNumber
#NSManaged var number_of_tasks: NSNumber
#NSManaged var price: NSNumber
#NSManaged var status: String
#NSManaged var subject: String
#NSManaged var taskImages: [String]
#NSManaged var theme: String
}
"id" is unique for each object. "propertiesToUpdate" consists of some fields like "maturity_date": 1470427641000, "status": "some status" and etc. "entityName" is "DBOrder". And privateContext is NSManagedObjectContext type to update entities in background
func updateCoreData(id: NSNumber, entityName: String, propertiesToUpdate: [String: AnyObject], privateContext: NSManagedObjectContext) -> Bool {
let batchRequest = NSBatchUpdateRequest(entityName: entityName)
batchRequest.predicate = NSPredicate(format: "id == %#", id)
if !doesOrderExists(entityName, id: id, context: privateContext) {
return false
}
batchRequest.propertiesToUpdate = propertiesToUpdate
batchRequest.resultType = .UpdatedObjectIDsResultType
do {
let res = try privateContext.executeRequest(batchRequest) as! NSBatchUpdateResult
let orderIDs = res.result as! [NSManagedObjectID]
return (orderIDs.count != 0) ? true : false
} catch {
print(error)
}
return false
}
This function is called for each object that has been loaded from server. If object is already existed then I update it else create the new one.
Finally, the problem: when I use batch update it works incorrect with NSNumber. It always puts NSNumber fields to nil and works as it should with String fields. So, what I'm doing wrong?
I need your help, I still have an beautiful EXC_BAD_ACCESS error on this line self.clinic!.copyWithDTO(clinicDTO).
Console : po self.clinic
Optional(<NSManagedObject: 0x7a7bd240> (entity: Clinic; id: 0x7a7bbe10 <x-coredata://7B916AD3-1989-426F-932F-0A62C755F2B4/Clinic/p1> ; data: <fault>))
I'm trying to fill properties on a sub entity in CoreData model by giving a DTO.
#objc(UserProfile)
class UserProfile: BaseStoredObject {
override class func entityName() -> String {
return "UserProfile"
}
override func copyWithDTO(dto: BaseDTO) {
if let userProfileDTO = dto as? UserProfileDTO {
self.id = userProfileDTO.id
self.login = userProfileDTO.login
self.password = userProfileDTO.password
self.lastname = userProfileDTO.lastname
self.email = userProfileDTO.email
self.createdOn = userProfileDTO.createdOn
self.gender = userProfileDTO.gender
self.userProfileType = userProfileDTO.userProfileType
self.firstname = userProfileDTO.firstname
self.fullname = userProfileDTO.fullname
if let clinicDTO = userProfileDTO.clinic {
if let unwrappedClinic = self.clinic {
unwrappedClinic.copyWithDTO(clinicDTO)
} else {
self.clinic = Clinic(entity: NSEntityDescription.entityForName("Clinic", inManagedObjectContext: self.managedObjectContext!)!, insertIntoManagedObjectContext: self.managedObjectContext)
self.clinic!.copyWithDTO(clinicDTO) // !! EXC_BAD_ACCESS (code=1, address=0x....)
}
}
} else {
fatalError("copyWithDTO: must be sent with UserProfileDTO")
}
}
}
#objc(Clinic)
class Clinic: BaseStoredObject {
override class func entityName() -> String {
return "Clinic"
}
override func copyWithDTO(dto: BaseDTO) {
if let clinicDTO = dto as? ClinicDTO {
self.id = clinicDTO.id
self.name = clinicDTO.name
self.phoneNumber = clinicDTO.phoneNumber
self.phoneNumber24hours = clinicDTO.phoneNumber24hours
self.nurseContactPhoneNumber = clinicDTO.nurseContactPhoneNumber
self.emergencyPhoneNumber = clinicDTO.emergencyPhoneNumber
self.internalClinicId = clinicDTO.internalClinicId
self.webserviceURL = ""
} else {
fatalError("copyWithDTO: must be sent with ClinicDTO")
}
}
}
extension UserProfile {
#NSManaged var id: String?
#NSManaged var login: String?
#NSManaged var password: String?
#NSManaged var lastname: String?
#NSManaged var firstname: String?
#NSManaged var email: String?
#NSManaged var createdOn: NSDate?
#NSManaged var userProfileType: NSNumber?
#NSManaged var gender: NSNumber?
#NSManaged var fullname: String?
#NSManaged var clinic: Clinic?
}
What I'm doing wrong ?
Thank you ;)
EDIT: BaseStoredObject is a subclass of NSManagedObject
Swift 2.0 Alamofire 2.0 Xcode 7 IOS 9
I have the next function which calls the API and retrieves the friend list in JSON format, convert the list in dictionary and append it to the Friendship NSObject
func GetFriends(completionHandler: ([FriendShip]?, NSError?) -> ()) {
Alamofire.request(Router.GetFriends(Test().getUserId())).responseJSON { (_, _, result) in
var friends = [FriendShip]()
switch result {
case .Success(let json):
if let responseObject = json as? [String: AnyObject], let hits = responseObject["hits"] as? [[String: AnyObject]] {
for dictionary in hits {
friends.append(FriendShip(dictionary: dictionary))
print(friends)
}
completionHandler(friends, nil)
}
case .Failure(_, let error):
completionHandler(nil, error as NSError)
}
}
the result of print(dictionary) is :
["_id": 546a6ef98e6df97032266, "friend": {
"_id" = 546a4b3e1f8d2c2630dd2;
name = "Daniela";
profileImageUrl = "https://api-static/profile/546a4b3e1f8d2c2630dd2.1.jpg";
statusTxt = "";
}]
["_id": 546a6f988e6df97032266, "friend": {
"_id" = 546a4ba51f8d2c2630dd2;
name = "Mara";
profileImageUrl = "https://api-static/profile/546a4ba51f8d2c2630dd2.1.jpg";
statusTxt = undefined;
}]
["_id": 546a70a18e6df97032266, "friend": {
"_id" = 546a4bd61f8d2c2630dd2;
name = "Alejandro";
profileImageUrl = "https://api-static/profile/546a4bd61f8d2c2630dd2.1.jpg";
statusTxt = "Marty";
}]
["_id": 546a715d8e6df97032266, "friend": {
"_id" = 546a4be01f8d2c2630dd2;
name = "Pedro";
profileImageUrl = "https://api-static/profile/546a4be01f8d2c2630dd1.1.jpg";
}]
classes Friendship and User
class FriendShip: NSObject{
var id: String?
var userId: String?
var user: User?
var friendId: String?
var friend: User?
var date: NSDate?
init(dictionary: [String: AnyObject]){
id = dictionary["id"] as? String
userId = dictionary["userId"] as? String
user = dictionary["user"] as? User
friendId = dictionary["friendId"] as? String
friend = dictionary["friend"] as? User
date = dictionary["date"] as? NSDate
}
override var description : String {
let friendString = friend!.name != nil ? friend!.name! : "nil"
let urlString = friend!.profileImageUrl != nil ? friend!.profileImageUrl! : "nil"
return "Friendship:\nfriend = \(friendString),\nurlString = \(urlString)"
}
}
class User: NSObject{
var id: String?
var name: String?
var statusTxt: String?
var profileImageUrl: String?
init(dictionary: [String: AnyObject]){
id = dictionary["id"] as? String
name = dictionary["name"] as? String
statusTxt = dictionary["statusTxt"] as? String
profileImageUrl = dictionary["profileImageUrl"] as? String
}
override var description : String {
let nameString = name != nil ? name! : "nil"
let profileImageUrlString = profileImageUrl != nil ? profileImageUrl! : "nil"
return "Friendship:\nname = \(nameString),\nprofileImageUrl = \(profileImageUrlString)"
}
}
How can I know/view/print if the friends.append function is working properly and its filling OK all the properties of the Friendship NSObject?
If I understand you correctly you need a way to print / debug the contents of your Friendship class.
NSObject implements the NSObjectProtocol which has a computed property description. That property returns a String that represents the contents of the class. It is the text you see when you print an object. So your Friendship class already inherits this description protocol from NSObject. But in your case it only prints the class name, because that is the default implementation.
So if you want to have a more meaningful description of your class, you have to override the description property:
class Friendship: NSObject {
var name: String?
var age: Int?
override var description : String {
let nameString = name != nil ? name! : "nil"
let ageString = age != nil ? String(age!) : "nil"
return "Friendship:\nname = \(nameString),\nage = \(ageString)"
}
}
I don't know what your actual Friendship class looks like, so I made my own, very simple class that only contains a name and an age.
So now when you have 2 instances of Friendship (one filled and one empty) and you print them, you can see the contents of that objects:
let friendship1 = Friendship()
friendship1.name = "John"
friendship1.age = 34
print(friendship1)
let friendship2 = Friendship()
print(friendship2)
Prints:
Friendship:
name = John,
age = 34
Friendship:
name = nil,
age = nil
UPDATE
In your case the overridden description vars should look like this:
class FriendShip: NSObject{
var id: String?
var userId: String?
var user: User?
var friendId: String?
var friend: User?
var date: NSDate?
init(dictionary: [String: AnyObject]){
id = dictionary["id"] as? String
userId = dictionary["userId"] as? String
user = dictionary["user"] as? User
friendId = dictionary["friendId"] as? String
friend = dictionary["friend"] as? User
date = dictionary["date"] as? NSDate
}
override var description : String {
let friendDescription = friend != nil ? friend!.description : "nil"
let userIdString = userId != nil ? userId! : "nil"
return "Friendship:\nfriend = \(friendDescription),\nuserId = \(userIdString)"
}
}
class User: NSObject{
var id: String?
var name: String?
var statusTxt: String?
var profileImageUrl: String?
init(dictionary: [String: AnyObject]) {
id = dictionary["id"] as? String
name = dictionary["name"] as? String
statusTxt = dictionary["statusTxt"] as? String
profileImageUrl = dictionary["profileImageUrl"] as? String
}
override var description : String {
let nameString = name != nil ? name! : "nil"
let profileImageUrlString = profileImageUrl != nil ? profileImageUrl! : "nil"
return "User:\nname = \(nameString),\nprofileImageUrl = \(profileImageUrlString)"
}
}
You can test it:
// test empty object
let friendship = FriendShip(dictionary: [String: AnyObject]())
print(friendship.description)
// test correct object
let user = User(dictionary: ["name": "John", "profileImageUrl": "http://image.com"])
let friendship2 = FriendShip(dictionary: ["friend": user, "userId": "1"])
print(friendship2.description)
Prints
Friendship:
friend = nil,
userId = nil
Friendship:
friend = User:
name = John,
profileImageUrl = http://image.com,
userId = 1