I'm using Realm-Cocoa in a mixed project. There have been a few head-scratchers, but now I'm truly stuck. I have tried tried several things but nothing helps.
This class compiles with no complaints,but crashes at runtime:
fatal error: use of unimplemented initializer 'init()' for class 'MyApp.Model'
And here's the class:
import Foundation
import Realm
import SwiftyJSON
class Model: RLMObject {
dynamic var contactId: String
dynamic var userId: String
dynamic var contactType: String
dynamic var firstName: String
dynamic var lastName: String
dynamic var middleName: String
dynamic var jobTitle:String
dynamic var department: String
dynamic var location: String
dynamic var serviceName: String
dynamic var serviceType : String
dynamic var emails : String
dynamic var addresses :String
dynamic var profilePictureSHA1 : String
dynamic var extNum : String
dynamic var fqExtNum : String
dynamic var ipbxId : String
dynamic var phone : String
dynamic var fax : String
dynamic var dispWhenNoext : Bool
dynamic var dispInContDir : Bool
override class func primaryKey() -> String? {
return "contactId"
}
init(
contactId: String,
userId: String,
contactType: String,
firstName: String,
lastName: String,
middleName: String,
jobTitle: String,
department: String,
location: String,
serviceName: String,
serviceType: String,
emails: String,
addresses: String,
profilePictureSHA1: String,
dispWhenNoext: Bool,
dispInContDir: Bool,
extNum: String,
fqExtNum: String,
ipbxId: String,
phone: String,
fax: String)
{
self.contactId = contactId
self.userId = userId
self.contactType = contactType
self.firstName = firstName
self.lastName = lastName
self.middleName = middleName
self.jobTitle = jobTitle
self.department = department
self.location = location
self.serviceName = serviceName
self.serviceType = serviceType
self.emails = emails
self.addresses = addresses
self.profilePictureSHA1 = profilePictureSHA1
self.dispInContDir = dispInContDir
self.dispWhenNoext = dispWhenNoext
self.extNum = extNum
self.fqExtNum = fqExtNum
self.ipbxId = ipbxId
self.phone = phone
self.fax = fax
super.init()
}
override static func ignoredProperties() -> [String] {
return ["contactFlag", "dttmCreated", "nickName", "customField1", "customField2", "customField3", "serviceId", "parentServiceId", "branchId", "hideInAA", "vooEnableFlag", "devLockDown", "tenantId", "serviceEmailId", "siteCustomerId", "branchCode", "accessCode"]
}
}
See the Realm documentation on custom subclass initialisers and Swift introspection issues at: https://realm.io/docs/swift/latest/#adding-custom-initializers-to-object-subclasses
According to that doco, you should make it a convenience method, rather than a designated initialiser. Worth a try, anyhow. Something like:
convenience init(
contactId: String,
userId: String,
contactType: String,
firstName: String,
lastName: String,
middleName: String,
jobTitle: String,
department: String,
location: String,
serviceName: String,
serviceType: String,
emails: String,
addresses: String,
profilePictureSHA1: String,
dispWhenNoext: Bool,
dispInContDir: Bool,
extNum: String,
fqExtNum: String,
ipbxId: String,
phone: String,
fax: String)
{
self.init() // NB: 'self' not 'super'
self.contactId = contactId
self.userId = userId
self.contactType = contactType
self.firstName = firstName
self.lastName = lastName
self.middleName = middleName
self.jobTitle = jobTitle
self.department = department
self.location = location
self.serviceName = serviceName
self.serviceType = serviceType
self.emails = emails
self.addresses = addresses
self.profilePictureSHA1 = profilePictureSHA1
self.dispInContDir = dispInContDir
self.dispWhenNoext = dispWhenNoext
self.extNum = extNum
self.fqExtNum = fqExtNum
self.ipbxId = ipbxId
self.phone = phone
self.fax = fax
}
Related
class Model {
let userId: Int
let username: String
private let description: String?
init(userId: Int, username: String, description: String?) {
self.userId = userId
self.username = username
self.description = description
}
}
class ModelDetail: Model {
let url: String
let detail: String
init(url: String, detail: String, userId: Int, username: String, description: String?) {
self.url = url
self.detail = detail
super.init(userId: userId, username: username, description: description)
}
}
I prepared this sample code to copy here. I don't want to inherit "description" value from Model class. When I try to something I am getting this error: Missing argument for parameter 'description' in call
Is it possible not to inherit some variable?
You cannot not inherit description, but you can assign a value nil to it, and simply ignore it.
If you can modify Model, you can change its init to
class Model {
// ...
init(userId: Int, username: String, description: String? = nil)
// ...
}
Since description is optional, we set it to nil by default, so ModelDetail doesn't need to set it at all:
class ModelDetail: Model {
let url: String
let detail: String
init(url: String, detail: String, userId: Int, username: String) {
self.url = url
self.detail = detail
super.init(userId: userId, username: username)
}
}
If you cannot change Model, then ModelDetail can invoke Model's init with nil for description:
class ModelDetail: Model {
// ...
init(url: String, detail: String, userId: Int, username: String) {
// ...
super.init(userId: userId, username: username, description: nil)
}
}
If you want to strictly adhere to the inheritance rules (which do not allow for "unused" fields), then you need to separate description from the model ModelDetail will be inheriting from. I.e.:
Have a base model, which only has userId and username
Both Model and ModelDetail will inherit from that base model, rather than each other:
class BasicModel {
let userId: Int
let username: String
init(userId: Int, username: String) {
self.userId = userId
self.username = username
}
}
class Model: BasicModel {
private let description: String?
init(userId: Int, username: String, description: String?) {
self.description = description
super.init(userId: userId, username: username)
}
}
class ModelDetail: BasicModel {
let url: String
let detail: String
init(url: String, detail: String, userId: Int, username: String) {
self.url = url
self.detail = detail
super.init(userId: userId, username: username)
}
}
I am fairly new to the swift language I am just taking a course I bought and I found myself running into the same error code a lot. "Type is ambiguous without more context" and I understand what it means (i think), SO. I am trying to assign a variable that has a class stored inside to another parameter of a class if that makes any sense. I understand that I'm trying to assign a class to a string, but I guess my question is how can I make this work? is there a type I don't know about in swift that would allow me to do such a thing?
class Adress {
let street: String
let city: String
let postalCode: String
init(street: String, city: String, postalCode: String) {
self.street = street
self.city = city
self.postalCode = postalCode
}
}
class PurchaseOrder {
var id: Int
var shippingAdress: (String)
var billingAdress: (String)
init(id: Int, shippingAdress: String, billingAdress:String) {
self.id = id
self.shippingAdress = shippingAdress
self.billingAdress = billingAdress
}
}
var defaultAddress = Adress(street: "555 North Pole Ave.", city: "North Pole City", postalCode: "H0H 0H0")
var aliceGift = PurchaseOrder(id: 001, shippingAdress: defaultAddress, billingAdress: defaultAddress)
// THE ERROR IS HERE ^^^^^^.
aliceGift.shippingAdress = "1000 North Pole Blvd."
print(aliceGift.billingAdress)
print(aliceGift.shippingAdress)
You have a custom Adress class so you should use it in your code. Change PurchaseOrder to
class PurchaseOrder {
var id: Int
var shippingAdress: Adress
var billingAdress: Adress
init(id: Int, shippingAdress: Adress, billingAdress:Adress) {
self.id = id
self.shippingAdress = shippingAdress
self.billingAdress = billingAdress
}
}
Of course you need to change the rest of the code as well so you assign an Adress object and not a String if you want to change any adress property
You've declared the types of shippingAddress and billingAddress incorrectly, as String instead of Address.
class Address {
let street: String
let city: String
let postalCode: String
init(street: String, city: String, postalCode: String) {
self.street = street
self.city = city
self.postalCode = postalCode
}
}
class PurchaseOrder {
var id: Int
var shippingAddress: Address
var billingAddress: Address
init(id: Int, shippingAddress: Address, billingAddress: Address) {
self.id = id
self.shippingAddress = shippingAddress
self.billingAddress = billingAddress
}
}
var defaultAddress = Address(street: "555 North Pole Ave.", city: "North Pole City", postalCode: "H0H 0H0")
var aliceGift = PurchaseOrder(id: 001, shippingAddress: defaultAddress, billingAddress: defaultAddress)
I am trying to implement a cache using CoreData.
Up until this point I've been storing models that are simple, however I have a model below that contains data types such as CodablePartialUser and CodableFeedItemType.
How should these types be modelled in CoreData?
Should I use the Data type and store them in a data format?
As CodableFeedItemType is an enum, should I store the raw value and convert between formats again?
struct CodablePartialUser: Equatable, Codable {
let userID: String
let firstName: String
let lastName: String
init(userID: String, firstName: String, lastName: String) {
self.userID = userID
self.firstName = firstName
self.lastName = lastName
}
}
enum CodableFeedItemType: String, Codable {
case recognition = "RECOGNITION"
case news = "COMPANY_NEWS"
}
struct CodableFeedItem: Codable {
let id: String
let type: CodableFeedItemType
let createdDate: Date
let createdBy: CodablePartialUser
let likesCount: Int
let commentsCount: Int
let externalID: String
let title: String?
let imageURL: URL?
init(id: String, type: CodableFeedItemType, createdDate: Date, createdBy: CodablePartialUser, likesCount: Int, commentsCount: Int, externalID: String, title: String?, imageURL: URL?) {
self.id = id
self.type = type
self.createdDate = createdDate
self.createdBy = createdBy
self.likesCount = likesCount
self.commentsCount = commentsCount
self.externalID = externalID
self.title = title
self.imageURL = imageURL
}
}
For the CodablePartialUser you can use relationship by creating a new Entity named as "CodablePartialUser"
For CodableFeedItemType you can use enum as like
enum CodableFeedItemType: String, Codable {
case recognition = "RECOGNITION"
case news = "COMPANY_NEWS"
}
extension CodableFeedItemEntity {
var type: CodableFeedItemType {
get {
return CodableFeedItemType(rawValue: typeRaw)!
}
set {
typeRaw = newValue.rawValue
}
}
}
Any suggestion on how to simplify this data struct? The data will be saved as a dictionary on the user's drive and when I read the data from the drive I have to convert them back to Member for easy accessing the properties.
I would like to have it typesafe.
struct Member {
var id: Int
var firstname: String
var lastname: String
var address: String?
var zipCode: Int?
var city: String?
enum Value: String {
case id = "id"
case firstname = "firstname"
case lastname = "lastname"
case address = "address"
case zipCode = "zipCode"
case city = "city"
}
var member: [String:Any] {
return [
Value.id.rawValue:Int(),
Value.firstname.rawValue:firstname,
Value.lastname.rawValue:lastname,
Value.address.rawValue:address ?? String(),
Value.zipCode.rawValue:zipCode ?? Int(),
Value.city.rawValue:city ?? String()
]
}
}
func memberToDic(member: Member) -> [String:Any] {
return [
Member.Value.firstname.rawValue:member.firstname,
Member.Value.lastname.rawValue:member.lastname,
Member.Value.address.rawValue:member.address ?? String(),
Member.Value.zipCode.rawValue:member.zipCode ?? Int(),
Member.Value.city.rawValue:member.city ?? String()
]
}
func dicToMember(dic: [String:Any]) -> Member {
return Member(
id: dic[Member.Value.id.rawValue] as! Int,
firstname: dic[Member.Value.firstname.rawValue] as! String,
lastname: dic[Member.Value.lastname.rawValue] as! String,
address: dic[Member.Value.address.rawValue] as? String,
zipCode: dic[Member.Value.zipCode.rawValue] as? Int,
city: dic[Member.Value.city.rawValue] as? String
)
}
Almost certainly, this is the correct implementation:
struct Member: Codable {
var id: Int
var firstName: String // "first name" is two words, so capitalize "name"
var lastName: String
var address: String // "No address" should be empty, not nil
var zipCode: String // ZIP codes are not integers
var city: String // "No city" should be empty, not nil
}
In order to save this as a plist, use PropertyListEncoder:
let data = try PropertyListEncoder().encode(member)
To read it, use PropertyListDecoder.
Codable automatically creates key mappings for your properties, so there's no need for Value.
You should strongly avoid creating or consuming [String: Any] dictionaries. These exist mostly due to Objective-C interfaces that could not generate strong types.
If address, zipCode, and city all should be set together, or not set together, then you should collect them into a single struct:
struct Address: Codable {
var streetAddress: String
var zipCode: String
var city: String
}
struct Member: Codable {
var id: Int
var firstName: String // "first name" is two words, so capitalize "name"
var lastName: String
var address: Address?
}
In this case, and Optional makes sense because "empty" is not the same thing as "missing."
How do I initialize an empty object in swift? This is what I have but it wants the parameters too
var userInfo:User = User()
init(email: String, isVerified: String, profileImageURL: String, reputation: String, twitterHandle: String, userName: String) {
self._email = email
self._isVerified = isVerified
self._profileImageURL = profileImageURL
self._reputation = reputation
self._twitterHandle = twitterHandle
self._userName = userName
}
Create the class/struct with optional properties like this
struct Employee {//struct or class
var name: String?
var number: String?
var position: String?
}
Then you can create an object without any value, with some value
let emp = Employee()
let emp = Employee(name: nil, number: nil, position: nil)
let emp = Employee(name: "abc", number: nil, position: "xyz")
By creating a init method with default values parameter can be ignored while creating an object
struct Employee {
var name: String?
var number: String?
var position: String?
init(name: String? = nil, number: String? = nil, position: String? = nil) {
self.name = name
self.number = number
self.position = position
}
}
let emp = Employee()
let emp = Employee(name: "abc", number: "124", position: "xyz")
let emp = Employee(name: "abc", position: "xyz")
let emp = Employee(number: "124")
let emp = Employee(name: "abc", number: "124")
I assume you are creating empty User objects so that the information can be filled in later on. There are two problems I can see with this: one, object properties will all have to be variables and second, it's easy to make mistakes and pass the wrong information since the object does not always correspond to a real entity.
A better approach would be to define a set of parameters that are mandatory for a User object to be defined, and let every other parameters either be optional parameters, or give them default values. For example, if we choose username and email to be mandatory, and let profile image be optional, and isVerified to have a default value of false:
class User {
var userName: String
var email: String
var isVerified: Bool
var profileImageURL: String?
init(userName: String, email: String, isVerified: Bool = false) {
self.userName = userName
self.email = email
self.isVerified = isVerified
}
}