I'm trying to create an app that saves data to CloudKit, I have that all sorted but when trying to initialise a new object I get an Extra Argument when initialising error.
Code with error:
func submitTask(){
var task: Task
task = CloudKitTask(task: Task){
task.shortDescription = self.txtShortDesc.text!
task.type = self.txtType.text!
task.reminder = self.txtReminder.text!
task.priority = self.txtPriority.text!
task.dueTime = self.txtDueTime.text!
task.dueDate = self.txtDueDate.text!
task.completed = "False"
task.className = self.txtClass.text!
task.additionalDetails = self.txtDetails.text
}
print(task)
}
Error: Extra argument 'task' in call on the task = CloudK... line
Task Class:
protocol Task {
var id: String? { get }
var shortDescription: String { get set }
var className: String { get set }
var type: String { get set }
var dueDate: String { get set }
var dueTime: String { get set }
var priority: String { get set }
var reminder: String { get set }
var completed: String { get set }
var additionalDetails: String { get set }
}
class CloudKitTask: Task {
let record: CKRecord
init(record: CKRecord){
self.record = record
}
init(task: Task){
record = CKRecord(recordType: "Task")
shortDescription = task.shortDescription
className = task.className
type = task.type
dueDate = task.dueDate
dueTime = task.dueTime
priority = task.priority
reminder = task.reminder
completed = task.completed
additionalDetails = task.additionalDetails
}
var className: String {
get {
return record.objectForKey("ClassName") as! String
}
set {
record.setObject(newValue, forKey: "ClassName")
}
}
var completed: String {
get {
return record.objectForKey("Completed") as! String
}
set {
record.setObject(newValue, forKey: "Completed")
}
}
var dueDate: String {
get {
return record.objectForKey("DueDate") as! String
}
set {
record.setObject(newValue, forKey: "DueDate")
}
}
var dueTime: String {
get {
return record.objectForKey("DueTime") as! String
}
set {
record.setObject(newValue, forKey: "DueTime")
}
}
var priority: String {
get {
return record.objectForKey("Priority") as! String
}
set {
record.setObject(newValue, forKey: "Priority")
}
}
var reminder: String {
get {
return record.objectForKey("Reminder") as! String
}
set {
record.setObject(newValue, forKey: "Reminder")
}
}
var shortDescription: String {
get {
return record.objectForKey("ShortDescription") as! String
}
set {
record.setObject(newValue, forKey: "ShortDescription")
}
}
var type: String {
get {
return record.objectForKey("Type") as! String
}
set {
record.setObject(newValue, forKey: "Type")
}
}
var additionalDetails: String {
get {
return record.objectForKey("AdditionalDetails") as! String
}
set {
record.setObject(newValue, forKey: "AdditionalDetails")
}
}
var id: String? {
return record.recordID.recordName
}
var createdAt: NSDate {
return record.creationDate!
}
var lastModifiedAt: NSDate {
return record.modificationDate!
}
}
I'm fairly new to programming with Swift and can't seem to find an answer that fixes my problem, if you know what I am doing wrong or what I can do to fix it please do point me in the right direction your help is very much appreciated.
If you need to see any more of my code please do ask...
What you probably meant here was to construct a CloudKitTask without first creating a CKRecord. In that case you should have an initializer for that:
convenience init() {
self.init(record: CKRecord(recordType: "Task"))
}
Then you can use it:
func submitTask(){
let task = CloudKitTask()
task.shortDescription = self.txtShortDesc.text!
task.type = self.txtType.text!
task.reminder = self.txtReminder.text!
task.priority = self.txtPriority.text!
task.dueTime = self.txtDueTime.text!
task.dueDate = self.txtDueDate.text!
task.completed = "False"
task.className = self.txtClass.text!
task.additionalDetails = self.txtDetails.text
print(task)
}
Related
I'm very new to Parse and Swift and I have this project I am working on and I am trying to create a search bar that displays all the items from the key "names" from my Parse database.
I have created this function that is supposed to take all the names and return them in a string array. But instead, the array never gets filled and all I get as a return is [].
class Offices {
var name: String
var phone: String
var location: String
init(name: String = "def_name", phone: String = "def_phone", location: String = "def_location") {
self.name = name
self.phone = phone
self.location = location
}
func retrieveName() -> [String] {
var models = [String]()
let queries = PFQuery(className: "Directory")
queries.findObjectsInBackground { (object, error) in
if let error = error {
// The query failed
print(error.localizedDescription)
} else if let object = object {
// The query succeeded with a matching result
for i in object{
models.append(i["name"] as? String ?? self.name)
}
} else {
// The query succeeded but no matching result was found
}
}
return models
}
findObjectsInBackground method is asynchronous. So you should change retrieveName function as below:
class Offices {
var name: String
var phone: String
var location: String
init(name: String = "def_name", phone: String = "def_phone", location: String = "def_location") {
self.name = name
self.phone = phone
self.location = location
// I call retrieveName here for example. You can call it where you want.
retrieveName() { (success, models) in
if success {
print(models)
} else {
print("unsuceess")
}
}
}
func retrieveName(completion: #escaping (_ success: Bool, _ models: [String]) -> Void) {
var models = [String]()
let queries = PFQuery(className: "Directory")
queries.findObjectsInBackground { (object, error) in
if let error = error {
// The query failed
print(error.localizedDescription)
completion(false, [])
} else if let object = object {
// The query succeeded with a matching result
for i in object{
models.append(i["name"] as? String ?? self.name)
}
completion(true, models)
} else {
completion(true, [])
// The query succeeded but no matching result was found
}
}
}
}
I need to set a nested table in core data. For eg, I have MenuList Table in which I have attributes (let's say they are name, id, address, email). So I want to add one attribute which childMenu which is array of custom objects, and again in it I have another attribute called subchildMenu with custom array objects. So I need to save all this data using coredata and manage functions for CRUD.
Below is the code, which I have tries, but stucked at saving childMenu.
import Foundation
import CoreData
extension MenuList {
#NSManaged public var sIcon : String?
#NSManaged public var sId: String?
#NSManaged public var sName : String?
//#NSManaged public var sChildMenu : NSSet?
#nonobjc public class func nsfetchRequest() -> NSFetchRequest< MenuList > {
return NSFetchRequest< MenuList >(entityName: "MenuList")
}
//------------------------------------------------------------------------------
// MARK:- Fetch Record
//------------------------------------------------------------------------------
class func fetchAllRecords() -> [MenuList]? {
let fetchRequest = MenuList.nsfetchRequest()
do {
let arr = try AppDelegate.shared.persistentContainer.viewContext.fetch(fetchRequest)
return arr
} catch {
Logger.error("\(self) - \(error.localizedDescription)")
return nil
}
}
//------------------------------------------------------------------------------
class func fetchAllRecords(forId: String) -> [MenuList]? {
let fetchRequest = MenuList.nsfetchRequest()
fetchRequest.predicate = NSPredicate(format: "sId = %#", forId)
do {
let arr = try AppDelegate.shared.persistentContainer.viewContext.fetch(fetchRequest)
return arr
} catch {
Logger.error("\(self) - \(error.localizedDescription)")
return nil
}
}
//------------------------------------------------------------------------------
// MARK:- Save Record
//------------------------------------------------------------------------------
class func saveRecord(_ tblData: [ListData]) {
for data in tblData {
if let tempId = data.id {
if let arrData = MenuList.fetchAllRecords(forId: tempId),arrData.count > 0 {
let tblData = arrData.first!
tblData.sId = tempId
if let childMenu = data.childMenu,childMenu.count > 0 {
// tblData.sChildMenu = NSSet.init(array: childMenu)
TblChildMenu.saveRecord(childMenu)
}
if let name = data.name {
tblData.sName = name
}
do {
try AppDelegate.shared.persistentContainer.viewContext.save()
Logger.log("\(self) Updated Here => =>")
} catch {
Logger.error("\(self) Update Error Here => \(error.localizedDescription)")
}
} else {
let viewContext = AppDelegate.shared.persistentContainer.viewContext
let tblStatusEntity = NSEntityDescription.entity(forEntityName: "MenuList", in: viewContext)
let tblStatusObj = NSManagedObject(entity: tblStatusEntity!, insertInto: viewContext) as! MenuList
tblStatusObj.sId = tempId
if let childMenu = data.childMenu,childMenu.count > 0 {
// tblStatusObj.sChildMenu = NSSet.init(object: childMenu)//NSSet.init(array: childMenu)
TblChildMenu.saveRecord(childMenu)
}
if let name = data.name {
tblStatusObj.sName = name
}
do {
try viewContext.save()
Logger.log("\(self) Saved Here => =>")
} catch {
Logger.error("\(self) Save Error Here => \(error.localizedDescription)")
}
}
}
}
}
//------------------------------------------------------------------------------
// MARK:- Delete Record
//------------------------------------------------------------------------------
class func deleteRecord(forId: String) {
let fetchRequest = MenuList.nsfetchRequest()
fetchRequest.predicate = NSPredicate(format: "sId = %#", forId)
do {
let arrData = try AppDelegate.shared.persistentContainer.viewContext.fetch(fetchRequest)
if arrData.count > 0 {
AppDelegate.shared.persistentContainer.viewContext.delete(arrData.first!)
}
} catch {
Logger.error("\(self) Delete = \(error.localizedDescription)")
}
}
}
Any Help will be appreciated.
I'm trying to save a custom class array to UserDefaults but it doesn't work. I get nil back on if let. I looked everywhere online. I'm using Swift 4.2
extension UserDefaults {
func saveReciters(_ reciters: [Reciter]) {
do {
let encodedData = try NSKeyedArchiver.archivedData(withRootObject: reciters, requiringSecureCoding: false)
self.set(encodedData, forKey: UD_RECITERS)
} catch {
debugPrint(error)
return
}
}
func getReciters() -> [Reciter] {
if let reciters = self.object(forKey: UD_RECITERS) as? Data {
return NSKeyedUnarchiver.unarchiveObject(with: reciters) as! [Reciter]
} else {
print("EMPTY RECITERS")
return [Reciter]()
}
}
}
UserInfo={NSDebugDescription=Caught exception during archival: -[_SwiftValue encodeWithCoder:]: unrecognized selector sent to instance 0x600001babcc0
Thats my class:
class Reciter: NSCoding {
private(set) public var name: String
private(set) public var image: UIImage?
private(set) public var surahs: [Surah]
private(set) public var documentID: String
private let quranData = QuranData()
init(name: String, image: UIImage?, surahCount: Int?, documentID: String) {
self.name = name
self.image = image
self.documentID = documentID
if let surahCount = surahCount {
surahs = Array(quranData.getAllSurahs().prefix(surahCount))
} else {
surahs = quranData.getAllSurahs()
}
}
func encode(with aCoder: NSCoder) {
}
required init?(coder aDecoder: NSCoder) {
}
}
On my Surah class i get nil back. All other properties i get back succesfully
Most often I see developer's use codeable, here I am using user as an example:
YourDataModel.swift
struct User: Codable {
var userId: String = ""
var name: String = ""
var profileImageData: Data? }
UserDefaults.swift
import Foundation
extension UserDefaults {
/// The current user of the application, see `./Models/User.swift`
var currentUser: User? {
get {
guard let userData = self.object(forKey: #function) as? Data else { return nil }
return try? JSONDecoder().decode(User.self, from: userData)
}
set {
guard let newuser = newValue else { return }
if let userData = try? JSONEncoder().encode(newuser) {
self.set(userData, forKey: #function)
}
}
}
}
Transform the data into json data... #function is the function or value name i.e.
// For the case the user doesn't yet exist.
if ( UserDefaults.standard.currentUser == nil ) {
// Create a new user
user = User()
// Generate an id for the user, using a uuid.
user?.userId = UUID().uuidString
} else {
// otherwise, fetch the user from user defaults.
user = UserDefaults.standard.currentUser
}
When I try to save to NSUserDefaults by adding a setter to my class variable (in this case the id and authToken variables, the values don't seem to be saved. When I run with a breakpoint on, the getter of id and authToken always return nil even after setting them with a value.
class CurrentUser {
static let defaultInstance = CurrentUser()
func updateUser(id id: String, authToken: String) {
self.id = id
self.authToken = authToken
}
var authToken: String? {
get {
if let authToken = NSUserDefaults.standardUserDefaults().objectForKey("userAuthToken") {
return (authToken as! String)
} else {
return nil
}
}
set {
NSUserDefaults.standardUserDefaults().setObject(authToken, forKey: "userAuthToken")
NSUserDefaults.standardUserDefaults().synchronize()
}
}
var id: String? {
get {
if let id = NSUserDefaults.standardUserDefaults().objectForKey("userId") {
return (id as! String)
} else {
return nil
}
}
set {
NSUserDefaults.standardUserDefaults().setObject(id, forKey: "userId")
NSUserDefaults.standardUserDefaults().synchronize()
}
}
}
However, when I pull the lines out to the updateUser function (one level higher), all works as expected.
class CurrentUser {
static let defaultInstance = CurrentUser()
func updateUser(id id: String, authToken: String) {
NSUserDefaults.standardUserDefaults().setObject(id, forKey: "userId")
NSUserDefaults.standardUserDefaults().synchronize()
NSUserDefaults.standardUserDefaults().setObject(authToken, forKey: "userAuthToken")
NSUserDefaults.standardUserDefaults().synchronize()
}
var authToken: String? {
get {
if let authToken = NSUserDefaults.standardUserDefaults().objectForKey("userAuthToken") {
return (authToken as! String)
} else {
return nil
}
}
}
var id: String? {
get {
if let id = NSUserDefaults.standardUserDefaults().objectForKey("userId") {
return (id as! String)
} else {
return nil
}
}
}
}
Why would this be? What am I missing? Does the { set } run on a different thread / mode where NSUserDefaults isn't accessible?
You must use newValue inside set method, value is still nil, or use didSet and then you can use variable.
As Alex said, you must use newValue in set method. Moreover, you can refer to this link for more detail:
Store [String] in NSUserDefaults (Swift)
I'm testing Realm, but I cant find a easy way to convert my object to JSON.
I need to push the data to my REST interface.
How can I do it using swift?
class Dog: Object {
dynamic var name = ""
}
class Person : Object {
dynamic var name = ""
let dogs = List<Dog>()
}
I'm trying something like this, but I can't iterate unknown objects (List)
extension Object {
func toDictionary() -> NSDictionary {
let props = self.objectSchema.properties.map { $0.name }
var dicProps = self.dictionaryWithValuesForKeys(props)
var mutabledic = NSMutableDictionary()
mutabledic.setValuesForKeysWithDictionary(dicProps)
for prop in self.objectSchema.properties as [Property]! {
if let objectClassName = prop.objectClassName {
if let x = self[prop.name] as? Object {
mutabledic.setValue(x.toDictionary(), forKey: prop.name)
} else {
//problem here!
}
}
}
return mutabledic
}
}
**sorry for ugly code.
I am also new to Realm but I think the easiest way is to reflect on Object's schema:
class Person: Object {
dynamic var name = ""
dynamic var age = 0
}
let person = Person()
let schema = person.objectSchema
let properties = schema.properties.map() { $0.name }
let dictionary = person.dictionaryWithValuesForKeys(properties) // NSDictionary
println(properties)
println(dictionary)
I think that I found the solution.
I'm not reliant about performance.
extension Object {
func toDictionary() -> NSDictionary {
let properties = self.objectSchema.properties.map { $0.name }
let dicProps = self.dictionaryWithValuesForKeys(properties)
var mutabledic = NSMutableDictionary()
mutabledic.setValuesForKeysWithDictionary(dicProps)
for prop in self.objectSchema.properties as [Property]! {
if let objectClassName = prop.objectClassName {
if let nestedObject = self[prop.name] as? Object {
mutabledic.setValue(nestedObject.toDictionary(), forKey: prop.name)
} else if let nestedListObject = self[prop.name] as? ListBase {
var objects = [AnyObject]()
for index in 0..<nestedListObject._rlmArray.count {
if let object = nestedListObject._rlmArray[index] as? Object {
objects.append(object.toDictionary())
}
}
mutabledic.setObject(objects, forKey: prop.name)
}
}
}
return mutabledic
}
}
Here is my solution. use unsafeBitCast to avoid cast fail warning.
extension Object {
func toDictionary() -> [String:AnyObject] {
let properties = self.objectSchema.properties.map { $0.name }
var dicProps = [String:AnyObject]()
for (key, value) in self.dictionaryWithValuesForKeys(properties) {
if let value = value as? ListBase {
dicProps[key] = value.toArray()
} else if let value = value as? Object {
dicProps[key] = value.toDictionary()
} else {
dicProps[key] = value
}
}
return dicProps
}
}
extension ListBase {
func toArray() -> [AnyObject] {
var _toArray = [AnyObject]()
for i in 0..<self._rlmArray.count {
let obj = unsafeBitCast(self._rlmArray[i], Object.self)
_toArray.append(obj.toDictionary())
}
return _toArray
}
}