public class User {
var id: Int
var fb_id: String?
var first_name: String?
var last_name: String?
var age: Int?
var distance: Int?
var login_at_pretty: String?
var login_at: Int?
var profile: Profile?
init(id: Int, fb_id: String?, first_name: String?, last_name: String?, age: Int?, distance: Int?, login_at_pretty: String?, login_at: Int?, profile: Profile?){
self.id = id
if let fb_id = fb_id {
self.fb_id = fb_id
}
if let first_name = first_name {
self.first_name = first_name
}
if let last_name = last_name {
self.last_name = last_name
}
if let age = age {
self.age = age
}
if let distance = distance {
self.distance = distance
}
if let login_at_pretty = login_at_pretty {
self.login_at_pretty = login_at_pretty
}
if let login_at = login_at {
self.login_at = login_at
}
if let profile = profile {
self.profile = profile
}
}
}
Is this the quickest way to do it? I feel like I'm over typing.
For your class, you're doing a lot of if-let statements that don't provide anything useful. ie:
if let fb_id = fb_id {
self.fb_id = fb_id
}
fb_id and self.fb_id are optionals, so the binding isn't necessary. Just do:
self.fb_id = fb_id
On that note however, if you're not planning on subclassing, using a struct would provide a memberwise initializer automagically:
public struct User {
var id: Int
var fb_id: String?
var first_name: String?
var last_name: String?
var age: Int?
var distance: Int?
var login_at_pretty: String?
var login_at: Int?
var profile: Profile?
}
Check out Memberwise Initializers for Structure Types in the swift docs
Related
I have some trouble to init() a class in another class.
I've been looking if I can find a solution in here but I wasn't able to.
If I write super.init() there comes another error because the function isn't existing.
I don't know where I have to initialize it.
I'd prefer to init the Address class in the open init from the Contact class but if I do so I can't access the Address class.
I think that it isn't a big mistake but I'm not able to find it.
open class Contact: Identifiable {
public var id: Int64?
var FirstName: String
var Name: String
var Phone: String
var Mail: String
var Birth: String
var News: Bool
open class Adress: Contact {
var Street: String
var Number: String
var PostalCode: String
var City: String
var Country: String // Error:'super.init' isn't called on all paths before returning from initializer
//If I add the Super.Init() there is an error because Super.Init() isn't existing and I don't know where to create it.
init(Street: String, Number: String, PostalCode: String, City: String, Country: String) {
self.Street=Street
self.Number=Number
self.PostalCode=PostalCode
self.City=City
self.Country=Country
}
}
public init(id: Int64, Firstname: String, Name: String, Phone: String, Mail: String, Birth: String, News: Bool) {
self.id = id
self.FirstName = Name
self.Name = Name
self.Phone = Phone
self.Mail = Mail
self.Birth = Birth
self.News = false
}
}
Technically you could do it this way:
class Contact: Identifiable {
public var id: Int64
var name: String
class Address: Contact {
var street: String
init(street: String, contact: Contact) {
self.street = street
super.init(id: contact.id, name: contact.name)
}
}
public init(id: Int64, name: String) {
self.id = id
self.name = name
}
}
let contact = Contact(id: 1, name: "name")
let address = Contact.Address(street: "street", contact: contact)
But maybe you want to model it in a way that a Contact has an Address:
class Contact: Identifiable {
public var id: Int64
var name: String
var address: Address
public init(id: Int64, name: String, address: Address) {
self.id = id
self.name = name
self.address = address
}
}
class Address: Identifiable {
var id: Int64
var street: String
public init(id: Int64, street: String) {
self.id = id
self.street = street
}
}
let address = Address(id: 1, street: "street")
let contact = Contact(id: 2, name: "name", address: address)
I have this request:
router.get("/fetchOngoingReleases") { (request) -> Future<[ReleaseOut]> in
return Release.query(on: request).filter(\.inprogress == true).all().map { releases in
var result: [ReleaseOut] = []
for r in releases {
var pageEvents: [Event] = []
let num = r.releaseUsers.query(on: request).filter(\.user.fbId ~~ "something").count()
var needAuthentication: Bool
if num == 0 {
needAuthentication = true
} else {
needAuthentication = false
}
let rOut = ReleaseOut(fbId: r.fbId, name: r.name, purpose: r.purpose, needAuthentication: needAuthentication)
result.append(rOut)
}
return result
}
}
}
It says I can not access (???) releaseUser.user.fbId in the query?
Here the data model:
and in code
final class Release: Content {
var id: Int?
var fbId: String
var inprogress: Bool?
var name: String
var purpose: String
/// Creates a new `Release`.
init(id: Int? = nil, fbId: String, name: String, purpose: String = "normal selling") {
self.id = id
self.fbId = fbId
self.name = name
self.purpose = purpose
}
}
extension Release {
var releaseUsers: Children<Release, ReleaseUser> {
return children(\.releaseId)
}
}
final class ReleaseUser: Content {
var id: Int?
var releaseId: Release.ID
var userId: User.ID
init(id: Int? = nil, releaseId: Release.ID, userId: User.ID) {
self.id = id
self.releaseId = releaseId
self.userId = userId
}
}
extension ReleaseUser {
var user: Parent<ReleaseUser, User> {
return parent(\.userId)
}
}
final class User: Content {
var id: Int?
var fbId: String
var name: String
init(id: Int? = nil, fbId: String, name: String) {
self.id = id
self.fbId = fbId
self.name = name
}
}
Ok so there are several things going on here, but the main concept is that you can't just jump across different tables like that - you need to use a JOIN to join the ReleaseUser table to the User table so you can then query on the fbId
Try changing your query to:
Release.query(on: request).filter(\.inprogress == true).join(\ReleaseUser.releaseId, to:\Release.Id).join(\ReleaseUser.userId, to:\User.Id).alsoDecode(User.self).all()
The alsoDecode will give you a tuple with the first position containing your original Release instance and the second containing the corresponding User instance. So, fbId should be available as:
r.1.fbId
In your case.
I am using separate class to save objects in the class. But it shows an error: "Return from initializer without initializing all stored properties". Please help me to resolve this.
class FetchedExpectedVisitors
{
var id: Int
var name: String
var email: String
var phone: String
var department_id: Int
var employee_id: Int
var location_id: Int
var image: String
var verification_code: String
var qr_code: String
var isVisited: Int
var company_id: Int
var purpose: String
var meeting_date: String
var meeting_time: String
var duration: String
var created_at: String
var updated_at: String
init(id: Int, name: String, email: String, phone: String, department_id: Int, employee_id: Int, location_id: Int, image: String, verification_code: String, qr_code: String, isVisited: Int, company_id: Int, purpose: String, meeting_date: String, meeting_time: String, duration: String, created_at: String, updated_at: String) {
self.id = id
self.name = name
self.email = email
self.phone = phone
self.department_id = department_id
self.location_id = location_id
self.image = image
self.verification_code = verification_code
self.qr_code = qr_code
self.isVisited = isVisited
self.company_id = company_id
self.purpose = purpose
self.meeting_date = meeting_date
self.meeting_time = meeting_time
self.duration = duration
self.created_at = created_at
self.updated_at = updated_at
}
}
Add self.employee_id = employee_id inside init().
Ok I thought its not a major issue but I am wrong. Currently I am working on a project where I get huge chunk of JSON return. I am fetching those and making my model. Now in my model I am checking if there any value is nil by guard statement. Here is a sample of my model:
import Foundation
import SwiftyJSON
class profileModel {
var _phone_no: String?
var _full_name: String?
var _image: String?
var _email: String?
var _profile_pic: String?
var _rating: Int?
var _dob: String?
var _gender: String?
var _firstName: String?
var _lastName: String?
required init?(phone_no: String, full_name: String, image: String, email: String, profile_pic: String, rating: Int, dob: String, gender: String, firstName: String, lastName: String) {
self._phone_no = phone_no
self._full_name = full_name
self._image = image
self._email = email
self._profile_pic = profile_pic
self._rating = rating
self._dob = dob
self._gender = gender
self._firstName = firstName
self._lastName = lastName
}
convenience init?(json: JSON){
guard let phone_no = json["phone_no"].string,
let full_name = json["full_name"].string,
let image = json["profile_pic"].string,
let email = json["email"].string,
let profile_pic = json["profile_pic"].string,
let rating = json["rating"].int,
let dob = json["dob"].string,
let gender = json["gender"].string,
let firstName = json["first_name"].string,
let lastName = json["last_name"].string else {
print("Profile Detail Model Error")
return nil
}
self.init(phone_no: phone_no, full_name: full_name, image: image, email: email, profile_pic: profile_pic, rating: rating, dob: dob, gender: gender, firstName: firstName, lastName: lastName)
}
}
But how can I prevent crashes when any key is missing from JSON return? Seems like when I check both key & values the class got really really big, there must be some better way.
Making properties optionals is a good approach, however you can take advantage of the new Codable from Swift 4 where you can parse JSON to any data model that conformance to Codable.
In your case you can write the model like this:
class ProfileModel: Codable {
var phone_no: String?
var full_name: String?
var profile_pic: String?
var email: String?
// var profile_pic: String?
var rating: String?
var dob: String?
var gender: String?
var first_name: String?
var last_name: String?
}
And when you need to decode from the server use:
let profile = try JSONDecoder().decode(ProfileModel.self, from: json1)
If you get an array of "Profile" just change the above line to:
let profiles = try JSONDecoder().decode([ProfileModel].self, from: json1)
There is no need to use the library SwiftyJSON any more.
You should have a look at the Codable protocol: The following Playground shows what happens, when you try to parse a Json, that is missing a particular key.
//: Playground - noun: a place where people can play
import Foundation
At first, we create our ProfileModel class and mock a related json.
class ProfileModel: Codable {
//...
var _firstName: String?
var _lastName: String?
}
let profile = ProfileModel()
profile._firstName = "Hans"
profile._lastName = "Peter"
let json = try! JSONEncoder().encode(profile)
Parsing works as expected:
do {
let profileAgain = try JSONDecoder().decode(ProfileModel.self, from: json)
print(profileAgain._firstName) // "Optional("Hans")\n"
print(profileAgain._lastName) // "Optional("Peter")\n"
} catch {
print("something went wrong")
}
So what happens, when we add another property to our class (_phone_no), that is not included in our Json? Nothing really changes, if this new property is optional:
class AnotherProfileModel: Codable {
//...
var _firstName: String?
var _lastName: String?
var _phone_no: Int?
}
do {
let anotherProfile = try JSONDecoder().decode(AnotherProfileModel.self, from: json)
print(anotherProfile._firstName) // "Optional("Hans")\n"
print(anotherProfile._lastName) // "Optional("Peter")\n"
print(anotherProfile._phone_no) // "nil\n"
} catch {
print("something went wrong")
}
But if this property is not an optional, the decoder will throw an error:
class AndYetAnotherProfileModel: Codable {
//...
var _firstName: String?
var _lastName: String?
var _phone_no: Int
}
do {
let andYetAnotherProfileModel = try JSONDecoder().decode(AndYetAnotherProfileModel.self, from: json)
} catch {
print("something went wrong") // "something went wrong\n"
}
I hope this working example will help you, to get a better understanding of the Codable protocol :)
Xcode is yelling error
But I don't know what happen. I've been searching and I think it might be something about casting and optional. The first one gives Initializer for conditional binding must have Optional type, not 'Date' and the second and third gives Initializer for conditional binding must have Optional type, not 'Double'
for article in (topic.articleArrays ?? nil)!{
if let articleId = article.id,
let articleHeadline = article.headline,
let articleSummary = article.summary,
let articleCity = article.city,
let articleState = article.state,
let articleDateretrieved = article.dateRetrieved,
let articlePublisher = article.publisher,
let articleLatitude = article.latitude,
let articleLongitude = article.longitude,
let articleRawBaseUrl = article.rawBaseUrl,
let articleRawUrl = article.rawUrl {
editedArticles?.append(NewsArticle(id: articleId, headline: articleHeadline, publisher: articlePublisher, summary: articleSummary, rawUrl: articleRawUrl, rawBaseUrl: articleRawBaseUrl, retrieved_date: articleDateretrieved, city: articleCity, state: articleState, latitude: articleLatitude, longitude: articleLongitude))
}
}
The struct for ediedArticles is NewsArticle which I've listed below
struct NewsArticle {
var id: String
var headline: String
var publisher: String
var summary: String
var rawUrl: String
var rawBaseUrl: String
var retrieved_date: Date
var city: String
var state: String
var latitude: Double
var longitude: Double
init(id: String, headline: String, publisher: String, summary: String, rawUrl: String, rawBaseUrl: String, retrieved_date: Date, city: String, state: String, latitude: Double, longitude: Double) {
self.id = id
self.headline = headline
self.publisher = publisher
self.summary = summary
self.rawUrl = rawUrl
self.rawBaseUrl = rawBaseUrl
self.retrieved_date = retrieved_date
self.city = city
self.state = state
self.latitude = latitude
self.longitude = longitude
}
}
topic.articlesArray have different data structure type which is SavedArticle (CoreData)
var articleArrays: [SavedArticle]? {
return self.articles?.allObjects as? [SavedArticle]
}
and have SavedArticle-CoreDataClass
var dateRetrieved: Date {
get {
return retrieved_date as Date
}
set(newDate) {
retrieved_date = newDate as NSDate
}
}
// TODO: Figured it out how to stored corrdinates in [Double]
convenience init?(id: String, headline: String, publisher: String, summary: String, retrieved_date: Date, city: String, state: String, latitude: Double, longitude: Double) {
guard let context = NaberCoreDataHandler.sharedInstance.managedContext else { return nil }
self.init(entity: SavedArticle.entity(), insertInto: context)
self.id = id
self.headline = headline
self.publisher = publisher
self.summary = summary
self.dateRetrieved = retrieved_date
self.city = city
self.state = state
self.latitude = latitude
self.longitude = longitude
}
with a SavedArticle-CoreDataProperties of following
#NSManaged public var city: String?
#NSManaged public var headline: String?
#NSManaged public var id: String?
#NSManaged public var publisher: String?
#NSManaged public var rawBaseUrl: String?
#NSManaged public var rawUrl: String?
#NSManaged public var retrieved_date: NSDate
#NSManaged public var state: String?
#NSManaged public var summary: String?
#NSManaged public var latitude: Double
#NSManaged public var longitude: Double
#NSManaged public var topics: SavedTopic?
It would be awesome if someone can help me figured it out what's the problem. I've beent rying for the whole day and nothing helps. Thank you! :)
if let (and guard let) can only be used to unwrap optional values. You can either assign those values with regular let statements on a separate line, or just pass them into the function directly since they don't need to be unwrapped.
article.dateRetrieved, article.latitude, and article.longitude are not Optionals. They are not declared with ? after their type names, so they can never be nil. There is therefore no need -- and in fact it is an error -- to try to unwrap them with an "if let" statement.
Remove the three lines of code that the compiler is complaining about.
When you create the NewsArticle and append it to editedArticles, you can pass those properties of article directly to the constructor of NewsArticle.