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)
}
}
Related
Currently I am working on a school assignment where we have to build an API using Vapor. I have a few basic API calls working and I am trying a bit more advanced API calls now but I can't get this to work.
I have this function addToParty that is being called when the URL /party/join/:partyID is called with a body
{
"id": "CC1FAC6B-A2B3-471C-A488-147300196981",
"username": "string",
"is_ready": true
}
I am trying to find a party by the partyId and add the user to the list of users of the party.
func addToParty (req: Request) throws -> EventLoopFuture<Party.Output> {
guard let id = req.parameters.get("partyID", as: UUID.self) else {
throw Abort(.badRequest)
}
let input = try req.content.decode(Party.JoinParty.self)
return Party.find(id, on: req.db)
.unwrap(or: Abort(.notFound))
.flatMap { element in
element.users.append(User(id: UUID(input.id), username: input.username, is_ready: input.is_ready))
return element.save(on: req.db)
.map{ Party.Output(code: "200") }
}
}
When I try the code above I get the error Fatal error: Children relation not eager loaded, use $ prefix to access: Children<Party, User>(for: [party_id]): file FluentKit/Children.swift, line 33 from the line
element.users.append(User(id: UUID(input.id), username: input.username, is_ready: input.is_ready))
When I comment this line the code runs and I get a return code.
I tried adding the prefix to element.$users and $User but then it complains about not being able to find element.$users and $User in scope.
Party model
import Fluent
import Vapor
final class Party: Model, Content {
static let schema = "parties"
struct JoinParty: Content {
let id: String
let username: String
let is_ready: Bool
}
struct Output: Content {
let code: String
}
#ID(key: .id)
var id: UUID?
#Field(key: "party_code")
var party_code: String
#Field(key: "host_id")
var host_id: UUID
#Field(key: "is_active")
var is_active: Bool
// change to Game when model is made
#Field(key: "selected_games")
var selected_games: [String]?
// change to Setting when model is made
#Field(key: "settings")
var settings: String
#Field(key: "results")
var results: Array<GameResult>?
#Children(for: \.$party)
var users: [User]
init() { }
init(id: UUID? = nil,
party_code: String,
host_id: UUID,
is_active: Bool,
selected_games: [String]? = nil,
settings: String,
results: Array<GameResult>? = nil) {
self.id = id
self.party_code = party_code
self.host_id = host_id
self.is_active = is_active
self.selected_games = selected_games
self.settings = settings
self.results = results
}
}
User model
import Fluent
import Vapor
final class User: Model, Content {
static let schema = "users"
struct Input: Content {
let id: UUID
let username: String
}
struct Output: Content {
let id: String
let username: String
}
#ID(key: .id)
var id: UUID?
#Field(key: "username")
var username: String
#Field(key: "is_ready")
var is_ready: Bool
#OptionalParent(key: "party_id")
var party: Party?
#Children(for: \.$user)
var gameResults: [GameResult]
init() {}
init(id: UUID? = nil, username: String, is_ready: Bool, partyID: UUID? = nil) {
self.id = id
self.username = username
self.is_ready = is_ready
self.$party.id = partyID
}
}
I have a similar function to update a username from a user already working which is almost the same thing.
func update(req: Request) throws -> EventLoopFuture<User.Output> {
let input = try req.content.decode(User.Input.self)
return User.find(input.id, on: req.db)
.unwrap(or: Abort(.notFound))
.flatMap { user in
user.username = input.username
return user.save(on: req.db)
.map { User.Output(id: user.id!.uuidString, username: user.username) }
}
}
Any help would be really appreciated.
Thank you in advance.
Unfortunately, adding children to a parent model is not that intuitive yet. I hope that someday we can get that added, but it's not there yet. Fluent 5 maybe?
Anyway, what you'll need to do instead is create your new User model, passing in the party's ID value to the partyID initializer parameter, and then save the User model.
let user = User(id: UUID(input.id), username: input.username, is_ready: input.is_ready, partyID: element.id)
return user.save(on: request.db)
So your method should end up looking like this:
func addToParty(req: Request) throws -> EventLoopFuture<Party.Output> {
guard let id = req.parameters.get("partyID", as: UUID.self) else {
throw Abort(.badRequest)
}
let input = try req.content.decode(Party.JoinParty.self)
return Party.find(id, on: req.db).unwrap(or: Abort(.notFound)).flatMap { element in
return User(
id: UUID(input.id),
username: input.username,
is_ready: input.is_ready,
partyID: element.id
).save(on: req.db)
}.transform(to: Party.Output(code: "200"))
}
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
}
}
}
I have an organization document with a Members collection inside of it and then a members document inside of that. Inside the members document includes a Map of a user which is a member. The Key is the UserID and 3 values (firstName, lastName, username). I am trying to load in this data into my "Event" class that holds a membersInvited Property that is a dictionary. Inside the Event class is a method to get this data called getOrgMembers(). Even though I have that data in firebase I am getting a nil value for my dictionary. I also am using Dispatch but kind of new to it.
Below is code in the Event Class:
var membersInvited: [Member: Bool]?
func getOrgMembers(dispatch: DispatchGroup?) {
let membRef = BandzDatabase.collection("Organizations").document(currentUser.currentOrgID!).collection("Members").document("members")
membRef.getDocument { (snapshot, error) in
if let error = error {
print (error.localizedDescription)
} else {
if let data = snapshot?.data() {
for (key,value) in data {
if let membArray = value as? [String: Any] {
let username = membArray["username"] as? String
let firstName = membArray["firstName"] as? String
let lastName = membArray["lastName"] as? String
let userID = key
let member = Member(username: username ?? "", firstName: firstName ?? "", lastName: lastName ?? "", userID: userID)
self.membersInvited?.updateValue(true, forKey: member)
}
}
}
}
dispatch?.leave()
}
}
struct Member: Hashable {
var username: String
var firstName: String
var lastName: String
var userID: String
init (username: String, firstName: String, lastName: String, userID: String) {
self.username = username
self.firstName = firstName
self.lastName = lastName
self.userID = userID
}
}
Below is were I call this method from another class:
func getMembers() {
showActivityIndicatory(uiView: self.view)
self.dispatchGroup.enter()
eventMade?.getOrgMembers(dispatch: self.dispatchGroup)
self.dispatchGroup.notify(queue: .main) {
//self.tableView.reloadData()
stopActivityIndicator()
print("happens")
print(self.eventMade?.membersInvited)
}
}
After some research, I discovered that since I never initilized the dictionary, whenever I was calling to append key-value paires it would not even run since it was an optional. So I changed the decleration to this:
var membersInvited: [Member: Bool] = [:]
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
}
}
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
}