How to convert one struct to another with same variables Swift (iOS)? - swift

I need help with converting one object to another. Might have searched 10-20 website didn't find any good answer.
public struct UniversityJoinChatViewModel {
public let id: Int?
public let name: String?
public init(nameOfModel model : UniversityGroupChatItem?) {
self.id = model?.id;
self.name = model?.name;
}
}
public struct UniversityGroupChatItem: Codable {
public let id: Int?
public let name: String?
public init(id: Int?, name: String?) {
self.id = id
self.name = name
}
}
I did this:
let say I have value UniversityGroupChatItem in variable universityGroupChatItem and my universityGroupChatItem contains is not nil and contains value. I tried this it did not work.
universityJoinChatViewModel = (universityGroupChatItem) as! UniversityJoinChatViewModel
The app crashed.
Then I tried:
map and
compactmap
None worked.
I am not getting how to convert UniversityGroupChatItem struct to UniversityJoinChatViewModel struct.
I do not understand how to convert one struct to another struct both has same number name variables.

You can't force cast one object into another (no matter struct, class, enum ect.) even if they are fully the same inside
You need to implement inits where one object takes fields from another one.
map is function to sequences, if You have only 1 object just init it with another one
Examples:
public struct UniversityJoinChatViewModel {
public let id: Int?
public let name: String?
public init(nameOfModel model : UniversityGroupChatItem?) {
self.id = model?.id;
self.name = model?.name;
}
}
public struct UniversityGroupChatItem: Codable {
public let id: Int?
public let name: String?
public init(id: Int?, name: String?) {
self.id = id
self.name = name
}
}
let universityGroupChatItem = UniversityGroupChatItem(id: 0, name: "name")
let universityJoinChatViewModel = UniversityJoinChatViewModel(nameOfModel: universityGroupChatItem)
let groupArray = Array(repeating: universityGroupChatItem, count: 10)
let joinArray = groupArray.map(UniversityJoinChatViewModel.init(nameOfModel:))

In your case, you already have the constructor that can help you to achieve what you want, so instead of trying to cast the object, create a new one:
universityJoinChatViewModel = UniversityJoinChatViewModel(nameOfModel: universityGroupChatItem)

Related

Inheritance from non-protocol type 'View' SwiftUI + UIKit [duplicate]

I need to use two classes with the same name in swift 5. For this, I have created those two classes in two different modules, but I am confused on how to use both the classes in an UIViewController
one of my class is Person which is in models > student module and another class is Person with is in the models module
I have tried importing class like
import class models.student.Person
class BookViewController: UIViewController {
var students:[Person] = [] //it should call models.student.Person
var people: [Person] = [] //it should call models.Person
...
but above Person class is pointing to models.Person only, It is not pointing to models.student.Person
Person class in models > Person.swift is
import Foundation
// MARK: - Person
public struct Person: Codable {
public let firstName: String?
public let lastName: String?
public let address: String?
public let phone: String?
enum CodingKeys: String, CodingKey {
case firstName = "first_name"
case lastName = "last_name"
case address = "address"
case phone = "phone"
}
public init(firstName: String?, lastName: String?, address: String?, phone: String?) {
self.firstName = firstName
self.lastName = lastName
self.address = address
self.phone = phone
}
}
and the models.student.Person.swift is
import Foundation
// MARK: - Person
public struct Person: Codable {
public let fullName: String?
public let educationalQualification: String?
public let college: String?
enum CodingKeys: String, CodingKey {
case fullName = "full_name"
case educationalQualification = "educational_qualification"
case college = "college"
}
public init(fullName: String?, educationalQualification: String?, college: String?) {
self.fullName = fullName
self.educationalQualification = educationalQualification
self.college = college
}
}
I need both the class in my BookViewController
I can't change the name of the class to a different one, I should use the same class name.
You could try typealias:
typealias StudentPerson = yourStudentFramework.Person
and then use it like:
import yourStudentFramework
class BookViewController: UIViewController {
var students:[StudentPerson] = [] //it should call yourStudentFramework.Person
var people: [Person] = [] //it should call models.Person
...

swift access modifiers correct usage

Suppose I have the following struct inside a StorageService framework :
struct Post {
public let author: String
public let description: String
public let image: String
public let likes: Int
public let views: Int
}
So to access its fields from another module I mark all fields with public keyword - it's clear. But should I mark the name Post itself to be public :
public struct Post ...
I tried both ways but I see no differences (with public struct Post and struct Post).
What is the right way to follow here?
The access modifier of the type itself will control the accessibility of the type and hence making any properties more accessible than the type itself is useless, since you cannot access properties of a type that you don't know about.
In order to be able to use the Post type from outside your framework, you need to declare Post as public.
This makes the type itself and all of its properties accessible from outside your framework:
public struct Post {
public let author: String
public let description: String
public let image: String
public let likes: Int
public let views: Int
}
On the other hand, if you don't want to expose some specific properties/methods publicly, you can always use an accessibility modifier that is stricter than the type's modifier.
public struct Post {
public let author: String
public let image: String
public let likes: Int
let description: String // can only be accessed from inside the module
private let views: Int // can only be accessed from the Post type itself
}

Vapor GraphQL schema field generic parameter 'ChildType' could not be inferred

I've started using Vapor as my BE framework with GraphQLKit and Graphiti, and I'm trying to define my model objects and schema, but I get an error Generic parameter 'ChildType' could not be inferred when trying to add optional child relationship as schema field.
The User model:
public final class User: Model {
public static let schema = "users"
#ID(key: .id)
public var id: UUID?
#OptionalField(key: "name")
public var name: String?
//MARK: Relations
#OptionalChild(for: \.$user)
public var record: Record?
public init() { }
public init(id: UUID? = nil,
about: String? = nil) {
self.id = id
self.name = name
}
}
The Record model:
public final class Record: Model {
public static let schema = "records"
#ID(key: .id)
public var id: UUID?
#Field(key: "type")
public var type: Int
//MARK: Relations
#OptionalParent(key:"user_id")
public var user: User?
public init() { }
public init(id: UUID? = nil,
type: Int,
userId: UUID? = nil) {
self.id = id
self.type = type
self.$user.id = userId
}
}
The scheme:
let schema = try! Schema<Resolver, Request> {
Scalar(UUID.self).description("Unique ID Type")
Type(User.self) {
Field("id", at: \.id)
Field("name", at: \.name)
Field("record", with: \.$record) ***Generic parameter 'ChildType' could not be inferred***
}
Type(Record.self) {
Field("id", at: \.id)
Field("type", at: \.type)
Field("user", with: \.$user)
}
Query {
Field("user", at: Resolver.getUser) {
Argument("id", at: \.id)
}
}
}
What am I doing wrong?
Seems like the right way to set this field on schema is:
Type(User.self) {
Field("id", at: \.id)
Field("name", at: \.name)
Field("record", at: \.$record, as: TypeReference<Record>?.self)
}

RealmSwift: storing an element with a timestamp

I am trying to define a wrapper around objects I want to store in Realm. The wrapper should contain an additional date object so that I can filter old objects. So far I have this
public final class RealmDateTaggedRealmObject: ObjectFacade {
#objc public dynamic var date: Date?
#objc public dynamic var value: ObjectFacade?
#objc private dynamic var id: String = ""
public override class func primaryKey() -> String? {
return #keyPath(id)
}
public convenience init<T: RealmMappable>(from object: RealmDateTagged<T>) {
self.init()
date = object.date
value = object.value.asRealmObject
id = object.primaryKey
}
}
The RealmMappable protocol enables transforming implementing entities into ObjectFacade. The ObjectFacade class is an empty class that inherits from Object, because I got an exception if I declared
#objc public dynamic var value: Object?
So I tried to be smart and created ObjectFacade. Turns out I'm not so smart cause it always stores nil. Also, value can't be a generic type because it is not supported in Objective-C.
Any suggestions?
Thanks!

Best approach to make class design if we have two class as bellow :

Best approach to make class design if we have two class as below:
class Teacher {
var name
var age
var TechId
}
class Student {
var name
var age
var StdID
}
I try it using that :
class Person {
var name
var age
}
class Student : Person {
var StdID
}
class Teacher : Person {
var TechID
}
But now problem is that student become teacher and vice versa.
Can you any one provided best solutions for that using Swift?
You said:
But now problem is that student become teacher and vice versa.
If you can change back and forth like this, I'd first suggest a concrete and distinct object to capture what precisely is transitioning from one to the other:
class Person {
var name: String
var age: Int
}
Note, in your example, you are considering this Person to be what other languages consider to be an abstract/virtual class. But I'm suggesting that you want to make this a concrete object (the actual person) that you instantiate.
The question then becomes how you represent "student" and "teacher". One simple pattern is to consider it a question of membership in some relevant collection:
typealias StudentID = String
var students: [StudentID: Person]
typealias TeacherID = String
var teachers: [TeacherID: Person]
In that case, transitioning from a student to a teacher (or vice versa) is merely a question of adding/removing from the appropriate dictionaries.
The above is a bit constrained, though. For example, what if you wanted to keep track of more student-specific properties (e.g. enrollment date, etc.) or teacher-specific properties (e.g. hire date, social security number, annual salary, etc.). This suggests you might want specific types for these student and teacher types:
class Student {
let studentID: String
let person: Person
}
class Teacher {
let teacherID: String
let person: Person
}
And then your students and teachers collections become simple arrays:
var students: [Student]
var teachers: [Teacher]
But by making the Person a property (rather than a base class), if you know which person is associated with a particular "student id", you can now associate that person with a particular "teacher id", too. But the idea is the same, it's merely a question of membership in the appropriate collection/type, not an issue of trying to change the inherent type of the person.
The alternative is a protocol oriented pattern:
protocol Person {
var name: String { get }
var age: Int { get }
}
struct Student: Person {
let studentID: String
var name: String
var age: Int
init(name: String, age: Int) {
studentID = UUID().uuidString
self.name = name
self.age = age
}
init(person: Person) {
self.init(name: person.name, age: person.age)
}
}
struct Teacher: Person {
let teacherID: String
var name: String
var age: Int
init(name: String, age: Int) {
teacherID = UUID().uuidString
self.name = name
self.age = age
}
init(person: Person) {
self.init(name: person.name, age: person.age)
}
}
This captures your notion that Person is an abstract type that simply conforms to having certain properties. It avoids any ambiguity that Person is not a type, itself, but merely a protocol to which types have to conform. You can only instantiate concrete Student and Teacher objects.
But then, if you want to create a Teacher from a Student, you can do:
let fred = Student(name: "Fred", age: 22)
let teacher = Teacher(person: fred)
Note, though, that this doesn’t “change” fred into a Teacher, but rather creates a new Teacher whose Person properties are copies of those of fred.
For Swift, I would recommend something like this:
protocol Person {
var name: String { get }
var age: Int { get }
}
struct Teacher: Person {
let id: Int
let name: String
let age: Int
}
struct Student: Person {
let id: Int
let name: String
let age: Int
}
Use a Protocol to define the person. And use a Struct for Teacher and Student because once created you would not change their details as a Struct is immutable. Both Teacher and Student conform to Person protocol.
To test if a person is a Teacher or Student, you could do this:
func test(person: Person) {
switch person {
case is Teacher:
print("teacher")
case is Student:
print("student")
default:
preconditionFailure("Unknown person type")
}
}