Appending PFObject to Array - EXC_BAD_ACCESS - ios

I am currently using Swift and Parse and have run into an issue which I haven't been able resolve for the past several hours.
On a button click, I am attempting to add an Employee object to an Event object's eventAttendee's array.
#IBAction func joinEvent(sender: AnyObject) {
var employee = Employee.currentUser()
employee.events.append(event)
employee.saveInBackgroundWithBlock(nil)
event.eventAttendees.append(employee)
event.saveInBackgroundWithBlock(nil)
}
The event is added to the employee events, but the employee is not added to the event attendees list. The function throws a EXC_BAD_ACCESS (code=1, address=0x0) on the append(employee) line, with no other error message.
My event class looks like this:
class VolunteerEvent : PFObject, PFSubclassing {
#NSManaged var eventName: String
#NSManaged var dateOfEvent: NSDate
#NSManaged var eventDescription: String
#NSManaged var eventURL: String?
#NSManaged var eventImage: PFFile
#NSManaged var contactEmail: String
#NSManaged var contactPhone: NSNumber
#NSManaged var eventOrganizer: Employee
#NSManaged var eventAttendees: [Employee]
class func parseClassName() -> String {
return "VolunteerEvent"
}
}
My Employee class extends PFUser, although when I print out the description of my employee I get that it is a PFUser. I can't tell if this is the issue. When I print out the event, it looks like I expect it to look. I also tried switching the eventAttendees to be an array of PFUser's instead of Employee's, but that didn't work either.
Any help would be much appreciated. Thank you.

I subclass my PFObjects this way,
class Person : PFObject, PFSubclassing {
var firstName: String {
get {
return objectForKey("firstName") as? String ?? ""
}
set {
setObject(newValue, forKey: "firstName")
}
}
}
This way if there is no string in the parse database, I don't get nil, i get an empty string.
You can do this with your array, in fact all your object properties.
If nothing is returned, then you will get an empty array of Employee, rather than a nil object - which will cause your crash when you try an append to it.

You need to initialize your array before adding to it. Try var eventAttendees: [Employee] = []

Related

EVReflection with NSManagedObject Crashes / not Working

hI: I've been using EVReflection to make our Network Layer Fully Restful and I Must say: AWESOME WORK! Thanks to #evermeer for this Library. you can get it here: https://github.com/evermeer/EVReflection
Now, to the Issue:
The Next Step is to get those Objects Straight into CORE DATA. Here is one of the Classes in Question
// Here is the Object With the EVReflectable Extension as the Documentation Claims:
import Foundation
import CoreData
import EVReflection
public class NGTripSummary: NSManagedObject { }
extension NGTripSummary: EVReflectable { }
// and HERE are the Object Properties:
// NGTripSummary+CoreDataProperties.swift
import Foundation
import CoreData
extension NGTripSummary {
#nonobjc public class func fetchRequest() -> NSFetchRequest<NGTripSummary> {
return NSFetchRequest<NGTripSummary>(entityName: "NGTripSummary")
}
#NSManaged public var carId: Int64
#NSManaged public var citiesVisited: NSObject?
#NSManaged public var cost: Double
#NSManaged public var distance: Double
#NSManaged public var globalStartDate: NSDate?
#NSManaged public var globalEndDate: NSDate?
#NSManaged public var kpl: Double
#NSManaged public var litres: Double
#NSManaged public var routeLocations: NSObject?
#NSManaged public var sessionId: Int64
#NSManaged public var localStartDate: NSDate?
#NSManaged public var localEndDate: NSDate?
#NSManaged public var duration: Int64
#NSManaged public var speed: Double
#NSManaged public var _id: Int64
#NSManaged public var sessionUuid: String?
#NSManaged public var tripUuid: String?
}
// . here is the JSON String that Represents a Demo Object:
let tripData = "{\"id\":26105240,\"userId\":25796277,\"carId\":25817551,\"vehicleId\":57812351,\"sessionUuid\":\"53324259-aa69-41c8-8f9e-c62bdb70f165\",\"tripUuid\":\"afdd8f55-6d14-4cf9-bd9f-5b6da47aaf93\",\"localStartDate\":1487170622490,\"localEndDate\":1487178323654,\"globalStartDate\":1487163422490,\"globalEndDate\":1487171123654,\"routeLocations\":null,\"litres\":24.7699,\"kpl\":0.0772,\"cost\":153.3258,\"distance\":1.9132,\"duration\":491.958,\"speed\":14.0}"
// and HERE is the Method I'm Trying to use to Create this Mock Object:
func makeMockData() {
let singleTrip = NGTripSummary(json: tripData)
print("Single Trip: \(singleTrip)")
}
// NOW: When Creating the Object, the Crash Happens HERE # class EVReflection:
// Call your own object validators that comply to the format: validate<Key>:Error:
do {
var setValue: AnyObject? = value as AnyObject?
/* LINE 923: CRASH HAPPENS HERE -> */ try anyObject.validateValue(&setValue, forKey: key)
anyObject.setValue(setValue, forKey: key)
} catch _ {
(anyObject as? EVReflectable)?.addStatusMessage(.InvalidValue, message: "Not a valid value for object `\(NSStringFromClass(type(of: (anyObject as AnyObject))))`, type `\(type)`, key `\(key)`, value `\(value)`")
print("INFO: Not a valid value for object `\(NSStringFromClass(type(of: (anyObject as AnyObject))))`, type `\(type)`, key `\(key)`, value `\(value)`")
}
////////////////// REASON FOR CRASH ////////////////////
[error] error: CoreData: error: Failed to call designated initializer on NSManagedObject class 'NGTripSummary'
CoreData: error: CoreData: error: Failed to call designated initializer on NSManagedObject class 'NGTripSummary'
//////////////////////////////////////////////////
-> Anybody, PLEASE HELP :-0
The error message describes the exact problem. You appear to be creating instances of NGTripSummary with this line of code:
let singleTrip = NGTripSummary(json: tripData)
But NGTripSummary is a subclass of NSManagedObject, and you're never calling the designated initializer for NSManagedObject. That's required. You must call init(entity:insertInto:) on NSManagedObject, or else use the factory method insertNewObject(forEntityName:into:) on NSEntityDescription to get a valid managed object. If you don't, you get this specific error and your app crashes.
If you need to create instances using tripData, you can do that, but you also need to provide a managed object context and an entity description. You could do that with a convenience initializer on your class, which would call the designated initializer as part of the initialization process.
EVReflection now has a Cocoapods subspec for CoreData. For more information see https://github.com/evermeer/EVReflection/tree/master/Source/CoreData
It will let you write code like this:\
let moc: NSManagedObjectContext = EVReflectionTestsData().moc // Your code for getting the NSManagedObjectContext.
let obj = CoreDataPerson(context: moc, json: "{\"firstName\" : \"Edwin\", \"lastName\" : \"Vermeer\"}")
try! moc.save() //TODO: implement error handling

Why I can't access an element of a class instance in Swift

I'm currently writing an iPhone application in Swift. I have a global class instance of my user database, like this:
var currentUser = UserDB()
class UserDB: Object {
dynamic var id:String = "0"
override class func primaryKey() -> String {
return "id"
}
var userName: String?
var firstName: String?
var lastName: String?
}
Then I try to print my user info with a print in another class:
UserDB {
id = 56826e22971f34731a07ba09;
userName = aze;
firstName = (null);
lastName = (null);
}
But if I try to print a single value, it won't works:
print(currentUser.userName)
Will print:
nil
Do you have any idea why?
By the way, is it a good idea to deal with user info like this? I put these info inside a Realm database on exit, when going to background, or after account upgrade.
You need to declare the properties as dynamic if you want Realm to map them. It seems that you did this only for the id property.
dynamic var userName: String?
dynamic var firstName: String?
dynamic var lastName: String?

Parse+Swift, "-[Swift._NSContiguousString objectId]: unrecognized selector sent to instance" error

I'm using Parse and I had a PFObject I was using to represent a "Job". It worked fined, but it was tedious always using setObject:forKey: and objectForKey: rather than accessing properties.
So, I decided to make a "proper" PFObject subclass. Now, every call made to "objectId" gives the above unrecognized selector error -- even calls that have nothing to do with my subclass.
I created my subclass "by the book", as far as I can tell (below), and I do call Job.registerSubclass() before Parse.setApplicationId: in my AppDelegate. Anybody seen this problem?
import Foundation
import Parse
class Job: PFObject, PFSubclassing {
#NSManaged var categoryName: String
#NSManaged var categoryId: String
#NSManaged var state: String
#NSManaged var details: String?
#NSManaged var jobDescription: String
#NSManaged var location: String
#NSManaged var dates: [String]
#NSManaged var images: PFFile?
#NSManaged var questionSequence: [String]?
#NSManaged var consumerResponseIndices: [Int]?
#NSManaged var isPosted: Bool
#NSManaged var bids: [AnyObject]?
override class func initialize() {
struct Static {
static var onceToken : dispatch_once_t = 0;
}
dispatch_once(&Static.onceToken) {
self.registerSubclass()
}
}
class func parseClassName() -> String {
return "Job"
}
}
I got the same issue before.
You may have this error when trying to convert NSArray/NSDictionary to String type, so it turns to NSContiguousString type.
You can check:
dates
questionSequence
consumerResponseIndices
bids
to see if this happened.
In my case the problem was :
if let countryLocale = (notification.userInfo![Constants.CountryLocale]!.firstObject as? String { code }
and solved with
if let countryLocale = (notification.userInfo![Constants.CountryLocale] as! [AnyObject]).first as? String { code }

Swift core data removing entries in one to many relationships

I'm using Xcode 6.4 and Swift in iOS 8.4 project
I have a model with one to many relationship
class Account: NSManagedObject {
#NSManaged var userId: Int
#NSManaged var accessToken: String?
#NSManaged var userName: String
#NSManaged var sex: String
#NSManaged var email: String
#NSManaged var avatarUrl: String?
#NSManaged var friends: NSSet
}
class User: NSManagedObject {
#NSManaged var id: Int
#NSManaged var userName: String
#NSManaged var sex: String
#NSManaged var email: String
#NSManaged var avatarUrl: String
}
When I'm trying to remove all friends it doesn't work:
extension Account {
func replaceFriends(friends:[User]) {
var friendsList = self.mutableSetValueForKey("friends")
friendsList.removeAllObjects()
friendsList.addObjectsFromArray(friends)
}
func getFriends() -> [User] {
return self.mutableSetValueForKey("friends").allObjects as! [User]
}
}
class AccountDao: BaseDao {
private class func findAccount() -> Account? {
if let result = moc.executeFetchRequest(NSFetchRequest(entityName: "Account"), error: nil) as? [Account] {
if (!result.isEmpty) {
return result[0]
}
}
return nil
}
class func getAccount() -> Account {
return findAccount() ??
NSEntityDescription.insertNewObjectForEntityForName("Account", inManagedObjectContext: moc) as! Account;
}
}
During saving I'm setting empty array:
class func saveObjectContext() -> Bool {
var error: NSError?
var account = AccountDao.getAccount()
account.replaceFriends([User]())
if !moc.save(&error) {
self.log.error("Error during saving context, \(error)")
return false
} else {
println("Count in log \(AccountDao.getAccount().getFriends().count)")
self.log.info("Info save context \(error)")
return true
}
}
In log it returns 0:
Count in log 0
But in ControllerView still I'm getting AccountDao.getAccount().getFriends().count == 1. Method replaceFriends works only first time when I fetch and save data. And it save changes for simple properties like userName but not for friends. Do you have any ideas?
I found that in relation one to many Account -> User without inverse relationship in User, after changing list in Account every user in list have to be marked that has changed (property updated == true). But it always was set to false.
I added additional property to User, and after every change of list I had to change this property like user.toUpdate = true. After this change everything is working fine.

Core data transient values with Swift

Does anyone know, or have an example of, how to handle core data transient values with Swift? I know to use #NSManaged before the properties, but can't figure out how to code the logic to build the transient values using Swift.
Check mark the transient field in your data model for particular attribute(e.g. sectionTitle).
Create class for that entity, it will look something like
class Message: NSManagedObject {
#NSManaged var body: String?
#NSManaged var time: NSDate?
#NSManaged var sectionTitle: String?
}
Edit it and make it like this:
class Message: NSManagedObject {
#NSManaged var body: String?
#NSManaged var time: NSDate?
var sectionTitle: String? {
return time!.getTimeStrWithDayPrecision()
//'getTimeStrWithDayPrecision' will convert timestamp to day
//just for e.g.
//you can do anything here as computational properties
}
}
Update- Swift4
Use #objc tag for Swift 4 as:
#objc var sectionTitle: String? {
return time!.getTimeStrWithDayPrecision()
}
We should use willAccessValueForKey and didAccessValueForKey to support KVO

Resources