Because EKEvent can not hold extra properties, I was thinking of creating my own class Event and inherit from EKCalendarItem (same as EKEvent class).
But I get a FrozenClass error, which is quite new to me. Does anybody have any idea of what that means? EKCalendarItem is an open class, so as far as I know I should be able to inherit from that. Or... am I wrong here?
The exact error:
'+[MyApp.Event frozenClass]: unrecognized selector sent to class
0x105667068'
My code:
class Event: EKCalendarItem {
// MARK: - Properties
var id: String
var startDate: Date
var endDate: Date
var isAllDay: Bool
// MARK: - Inits
init?(id: String, dictionary: [String: Any]) {
guard
let title = dictionary["title"] as? String,
let startDate = dictionary["startDate"] as? Timestamp,
let endDate = dictionary["endDate"] as? Timestamp,
let isAllDay = dictionary["isAllDay"] as? Bool
else { return nil }
self.id = id
self.startDate = startDate.dateValue()
self.endDate = endDate.dateValue()
self.isAllDay = isAllDay
super.init()
self.location = dictionary["location"] as? String
self.title = title
self.notes = dictionary["notes"] as? String
}
convenience init?(snapshot: QueryDocumentSnapshot) {
self.init(id: snapshot.documentID, dictionary: snapshot.data())
}
}
Related
Im gettin Couldn't comunicate with a helper application in the console when I'm trying to save a local notification in UNUserNotificationCenter with userInfo.
If I remove de userInfo instruccion works perfectly.
This is the class that implement NSCoding methods. In de notification.userInfo I'm storing an object of this class
class Homework: NSObject, NSCoding, NSSecureCoding {
let name: String
let homeworkDescription: String
let date: Date
let score: Double
let status: String
let subject: String
let db = Firestore.firestore()
static var supportsSecureCoding: Bool {
return true
}
init(name: String, description: String, date: Date, score: Double, status: String, subject: String){
self.name = name
self.homeworkDescription = description
self.date = date
self.score = score
self.status = status
self.subject = subject
}
func encode(with coder: NSCoder) {
coder.encode(name, forKey: Keys.name.rawValue)
coder.encode(homeworkDescription, forKey: Keys.description.rawValue)
coder.encode(date, forKey: Keys.date.rawValue)
coder.encode(score, forKey: Keys.score.rawValue)
coder.encode(status, forKey: Keys.status.rawValue)
coder.encode(subject, forKey: Keys.subject.rawValue)
}
required convenience init?(coder: NSCoder) {
let decodedName = coder.decodeObject(forKey: Keys.name.rawValue) as! String
let decodedDescription = coder.decodeObject(forKey: Keys.description.rawValue) as! String
let decodedDate = coder.decodeObject(forKey: Keys.date.rawValue) as! Date
let decodedScore = coder.decodeDouble(forKey: Keys.score.rawValue)
let decodedStatus = coder.decodeObject(forKey: Keys.status.rawValue) as! String
let decodedSubject = coder.decodeObject(forKey: Keys.subject.rawValue) as! String
self.init(name: decodedName, description: decodedDescription, date: decodedDate, score: decodedScore, status: decodedStatus, subject: decodedSubject)
}
enum Keys: String {
case name = "Name"
case description = "Description"
case date = "Date"
case score = "Score"
case status = "Status"
case subject = "Subject"
}
This is the code that add the notification and when I get the error:
for notification in notifications
{
let content = UNMutableNotificationContent()
content.title = notification.title
content.subtitle = notification.subTitle
content.body = notification.body
content.sound = .default
content.badge = UIApplication.shared.applicationIconBadgeNumber as NSNumber
content.targetContentIdentifier = notification.type
content.userInfo[notification.type] = notification.homework
let trigger = UNCalendarNotificationTrigger(dateMatching: notification.dateTime, repeats: false)
let request = UNNotificationRequest(identifier: notification.id, content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request) { error in
if let error = error{
print("This is the error: " + error.localizedDescription)
}else{
print("Notification scheduled! --- ID = \(notification.id)")
}
}
This is the notification class:
class LocalNotification {
var id: String
var title: String
var subTitle: String
var dateTime: DateComponents
var type: String
var body: String
var homework: Homework
init(id: String, title: String, subtitle: String, dateTime: DateComponents, type: String, description: String, homeWork: Homework) {
self.id = id
self.title = title
self.subTitle = subtitle
self.dateTime = dateTime
self.type = type
self.body = description
self.homework = homeWork
}
Does anyone one know why this happened?
I am new to Swift, but have some basic experience with Objective-C programming, and Swift seems much simpler.
However, I can't quite understand the struct thing. I followed a tutorial on how to use Firebase Realtime Database, and this tutorial were using a model to store the data.
But when I modified the struct with additional properties, the previously saved entries in the database is not showing up. I think it's because the model doesn't recognize the object in the database because it has different properties, but how can I make a property optional? So that old entries in the database with different structure (missing properties) are still valid and showing up?
Here is the model. The new property added is all the references to the description.
import Foundation
import Firebase
struct InsuranceItem {
let ref: DatabaseReference?
let key: String
let name: String
let timestamp: Int
let itemValue: Int
let description: String?
let userId: String?
init(name: String, timestamp: Int, itemValue: Int = 0, description: String = "", userId: String, key: String = "") {
self.ref = nil
self.key = key
self.name = name
self.timestamp = Int(Date().timeIntervalSince1970)
self.itemValue = itemValue
self.description = description
self.userId = userId
}
init?(snapshot: DataSnapshot) {
guard
let value = snapshot.value as? [String: AnyObject],
let name = value["name"] as? String,
let timestamp = value["timestamp"] as? Int,
let itemValue = value["itemValue"] as? Int,
let description = value["description"] as? String,
let userId = value["userId"] as? String else { return nil }
self.ref = snapshot.ref
self.key = snapshot.key
self.name = name
self.timestamp = timestamp
self.itemValue = itemValue
self.description = description
self.userId = userId
}
func toAnyObject() -> Any {
return [
"name": name,
"timestamp": timestamp,
"itemValue": itemValue,
"description": description!,
"userId": userId!
]
}
}
The problematic bit is your failable init, init?(snapshot: DataSnapshot). You fail the init even if an Optional property is missing, which is incorrect. You should only include the non-Optional properties in your guard statement, all others should simply be assigned with the optional casted value.
init?(snapshot: DataSnapshot) {
guard
let value = snapshot.value as? [String: Any],
let name = value["name"] as? String,
let timestamp = value["timestamp"] as? Int,
let itemValue = value["itemValue"] as? Int else { return nil }
self.ref = snapshot.ref
self.key = snapshot.key
self.name = name
self.timestamp = timestamp
self.itemValue = itemValue
// Optional properties
let description = value["description"] as? String
let userId = value["userId"] as? String
self.description = description
self.userId = userId
}
Unrelated to your question, but your toAnyObject function is unsafe, since you are force-unwrapping Optional values. Simply keep them as Optionals without any unwrapping and add as Any to silence the warning for implicit coersion.
func toAnyObject() -> Any {
return [
"name": name,
"timestamp": timestamp,
"itemValue": itemValue,
"description": description as Any,
"userId": userId as Any
]
}
Swift 4 / Xcode 9.3 / OS X 10.13.4 / iOS 11.3 & 11.2.6
I'm trying to build my app and I'm getting the above error message. I've checked the code over and over and over and I can't figure out why I'm getting this error. I'm not certain which part of the code you need to see, but here is the page I'm getting the error on. The error code is flagging the very last line of code.
import UIKit
import os.log
class Bonus: NSObject, NSCoding {
//MARK: Archiving Paths
static let DocumentsDirectory = FileManager().urls(for: .documentDirectory, in: .userDomainMask).first!
static let ArchiveURL = DocumentsDirectory.appendingPathComponent("bonuses")
//MARK: Properties
var bonusCode: String
var category: String
var name: String
var value: Int
var city: String
var state: String
var photo: UIImage?
//MARK: Initialization
init?(bonusCode: String, category: String, name: String, value: Int, city: String, state: String, photo: UIImage?) {
// The name must not be empty.
guard !name.isEmpty else {
return nil
}
// The value must not be negative.
guard (value >= 0) else {
return nil
}
// Initialize stored properties.
self.bonusCode = bonusCode
self.category = category
self.name = name
self.value = value
self.city = city
self.state = state
self.photo = photo
}
//MARK: Types
struct PropertyKey {
static let bonusCode = "bonusCode"
static let category = "category"
static let name = "name"
static let value = "value"
static let city = "city"
static let state = "state"
static let photo = "photo"
}
//MARK: NSCoding
func encode(with aCoder: NSCoder) {
aCoder.encode(bonusCode, forKey: PropertyKey.bonusCode)
aCoder.encode(category, forKey: PropertyKey.category)
aCoder.encode(name, forKey: PropertyKey.name)
aCoder.encode(value, forKey: PropertyKey.value)
aCoder.encode(city, forKey: PropertyKey.city)
aCoder.encode(state, forKey: PropertyKey.state)
aCoder.encode(photo, forKey: PropertyKey.photo)
}
required convenience init?(coder aDecoder: NSCoder) {
// The name is required. If we cannot decode a name string, the initializer should fail.
guard let bonusCode = aDecoder.decodeObject(forKey: PropertyKey.bonusCode) as? String else {
os_log("Unable to decode the Code for a Bonus object.", log: OSLog.default, type: .debug)
return nil
}
// Because photo is an optional property of Meal, just use conditional cast
let photo = aDecoder.decodeObject(forKey: PropertyKey.photo) as? UIImage
let category = aDecoder.decodeObject(forKey: PropertyKey.category)
let value = aDecoder.decodeInteger(forKey: PropertyKey.value)
let city = aDecoder.decodeObject(forKey: PropertyKey.city)
let state = aDecoder.decodeObject(forKey: PropertyKey.state)
// Must call designated initializer.
self.init(bonusCode: String, category: String, name: String, value: Int, city: String, state: String, photo: UIImage?)
}
}
The error is flagging on the bonusCode: String, specifically on the S in String.
I'm pretty new to programming, but I only found one other search result for this specific question, and the other similar ones seemed to be very specific to the code being used.
You have to pass the decoded values rather than the types in the last line and the line to decode the name is missing and you have to cast the other string objects. The force unwrapping is safe because all non-optional values are encoded properly.
let name = aDecoder.decodeObject(forKey: PropertyKey.name) as! String
let category = aDecoder.decodeObject(forKey: PropertyKey.category) as! String
let value = aDecoder.decodeInteger(forKey: PropertyKey.value)
let city = aDecoder.decodeObject(forKey: PropertyKey.city) as! String
let state = aDecoder.decodeObject(forKey: PropertyKey.state) as! String
...
self.init(bonusCode: bonusCode, category: category, name: name, value: value, city: city, state: state, photo: photo)
self.init(bonusCode: String,
category: String,
name: String,
value: Int,
city: String,
state: String,
photo: UIImage?)
This is a function call, not a function declaration.
You are passing types instead of values into a function call.
You should be doing this instead:
self.init(bonusCode: bonusCode,
category: category,
name: name,
value: value,
city: city,
state: state,
photo: photo)
So finally, your init should look like (with a little improvement):
required convenience init?(coder aDecoder: NSCoder) {
//NOTE: `decodeObject(forKey:)` returns optional `Any` and hence all those `as? String`
//name was missing
let name = aDecoder.decodeObject(forKey: PropertyKey.name) as? String
let bonusCode = aDecoder.decodeObject(forKey: PropertyKey.bonusCode) as? String
let category = aDecoder.decodeObject(forKey: PropertyKey.category) as? String
let value = aDecoder.decodeInteger(forKey: PropertyKey.value)
let city = aDecoder.decodeObject(forKey: PropertyKey.city) as? String
let state = aDecoder.decodeObject(forKey: PropertyKey.state) as? String
let photo = aDecoder.decodeObject(forKey: PropertyKey.photo) as? UIImage
/*
Only photo is optional in order to init but the rest are required
Hence the optional binding for the rest below
*/
if let name = name,
let bonusCode = bonusCode,
let category = category,
let city = city,
let state = state {
// Must call designated initializer.
self.init(bonusCode: bonusCode,
category: category,
name: name,
value: value,
city: city,
state: state,
photo: photo)
}
else {
/*
Some required object/s were missing so we can't call the
designated initializer unless we want to give default values.
Hence return nil
*/
return nil
}
}
Getting several "Cannot convert value of type Bool to expected argument type String" errors. The method for encoding expects a string but it is getting a Bool?
Here is the code. See the attached image for errors.
import Foundation
class Restaurant {
var name = ""
var item = ""
var location = ""
var image = ""
var isVisited = false
var phone = ""
var rating = ""
init(name: String, item: String, location: String, phone: String, image: String, isVisited: Bool) {
self.name = name
self.item = item
self.location = location
self.phone = phone
self.image = image
self.isVisited = isVisited
}
class func makeNewsItem(_ notificationDictionary: [String: AnyObject]) -> Restaurant? {
if let name = notificationDictionary["name"] as? String,
let phone = notificationDictionary["phone"] as? String,
let location = notificationDictionary["location"] as? String {
let date = Date()
let image = ""
let visited = false
let item = ""
let newsItem = Restaurant(name: name, item: item, location: location, phone: phone, image: image, isVisited: visited)
NotificationCenter.default.post(name: Notification.Name(rawValue: RestaurantTableViewController.RefreshNewsFeedNotification), object: self)
return newsItem
}
return nil
}
}
extension Restaurant: NSCoding {
struct CodingKeys {
static var Name = "name"
static var Item = "item"
static var Location = "location"
static var Image = "image"
static var IsVisited:Bool = false
static var Phone = "phone"
static var Rating = "rating"
}
convenience init?(coder aDecoder: NSCoder) {
if let name = aDecoder.decodeObject(forKey: CodingKeys.Name) as? String,
let location = aDecoder.decodeObject(forKey: CodingKeys.Location) as? Date,
let phone = aDecoder.decodeObject(forKey: CodingKeys.Phone) as? String {
let date = Date()
let image = aDecoder.decodeObject(forKey: CodingKeys.Image) as? String
let visited:Bool = aDecoder.decodeBool(forKey: CodingKeys.IsVisited) as? String
let item = aDecoder.decodeObject(forKey: CodingKeys.Item) as? String
self.init(name: name, item: item, location: location, phone: phone, image: image, isVisited: visited)
} else {
return nil
}
}
func encode(with aCoder: NSCoder) {
aCoder.encode(name, forKey: CodingKeys.Name)
aCoder.encode(location, forKey: CodingKeys.Location)
aCoder.encode(phone, forKey: CodingKeys.Phone)
aCoder.encode(item, forKey: CodingKeys.Item)
aCoder.encode(image, forKey: CodingKeys.Image)
aCoder.encode(isVisited, forKey: CodingKeys.IsVisited)
aCoder.encode(rating, forKey: CodingKeys.Rating)
}
}
You can´t add a bool value to the forKey. This has to be a string value, so change it from:
aCoder.encode(isVisited, forKey: CodingKeys.IsVisited)
To:
aCoder.encode(isVisited, forKey: "IsVisited")
Same for:
let visited:Bool = aDecoder.decodeBool(forKey: CodingKeys.IsVisited) as? String
To:
let visited:Bool = aDecoder.decodeBool(forKey: "IsVisited") // note, no need for as? String here
I am trying to cast a PFObject to a custom class in Swift and I read a lot of post about it and in all of then I need to inherit my class from PFObject. The problem is that my class is already inherited from NSObject and there is a conflict between then.
Is there another way to cast a PFObject to a custom class?
Usuario.swift
class Usuario: NSObject, NSCoding {
//MARK: Propriedades
var nome: String?
var foto: String?
var dataNascimento: Date?
var numeroTelefone: String?
var pais: PaisCodigo?
var telefoneE164: String?
var objectId: String?
var created: Date?
var updated: Date?
override init() {}
required init(coder aDecoder: NSCoder) {
nome = aDecoder.decodeObject(forKey: "nome") as? String
foto = aDecoder.decodeObject(forKey: "foto") as? String
dataNascimento = aDecoder.decodeObject(forKey: "dataNascimento") as? Date
numeroTelefone = aDecoder.decodeObject(forKey: "numeroTelefone") as? String
pais = aDecoder.decodeObject(forKey: "pais") as? PaisCodigo
telefoneE164 = aDecoder.decodeObject(forKey: "telefoneE164") as? String
objectId = aDecoder.decodeObject(forKey: "objectId") as? String
created = aDecoder.decodeObject(forKey: "created") as? Date
updated = aDecoder.decodeObject(forKey: "updated") as? Date
}
func encode(with aCoder: NSCoder) {
if let nomeUsuario = nome {
aCoder.encode(nomeUsuario, forKey: "nome")
}
if let fotoUsuario = foto {
aCoder.encode(fotoUsuario, forKey: "foto")
}
if let dataNascimentoUsuario = dataNascimento {
aCoder.encode(dataNascimentoUsuario, forKey: "dataNascimento")
}
if let numeroTelefoneUsuario = numeroTelefone {
aCoder.encode(numeroTelefoneUsuario, forKey: "numeroTelefone")
}
if let paisUsuario = pais {
aCoder.encode(paisUsuario, forKey: "pais")
}
if let telefoneE164Usuario = telefoneE164 {
aCoder.encode(telefoneE164Usuario, forKey: "telefoneE164")
}
if let objectIdUsuario = objectId {
aCoder.encode(objectIdUsuario, forKey: "objectId")
}
if let createdUsuario = created {
aCoder.encode(createdUsuario, forKey: "created")
}
if let updatedUsuario = updated {
aCoder.encode(updatedUsuario, forKey: "updated")
}
}
}
The Parse result using an objectId returns me this result:
<Usuario: 0x6080000abb20, objectId: 7NwpmD81w3, localId: (null)> {
nome = "Pablo Cavalcante";
numeroTelefone = 67992497386;
pais = "<PaisCodigo: 0x6080000abb80, objectId: rA5wdIWEFt, localId: (null)>";
telefoneE164 = "+5567992497386"; }
So it returns an Usuario object and I need to cast it.
You can use PFSubclassing. I see that you're declaring a user class so you could just subclass PFUser and then write something like this:
class User: PFUser, PFSubclassing {
//MARK: Propriedades
dynamic var nome: String?
dynamic var foto: String?
dynamic var dataNascimento: Date?
dynamic var numeroTelefone: String?
dynamic var pais: PaisCodigo?
dynamic var telefoneE164: String?
dynamic var objectId: String?
dynamic var created: Date?
dynamic var updated: Date?
}
Of course if you're using the init(with:) and encode(with:) you have to implement it...