Create instance from class using other class instance - swift

So i came across this case, an already published application needed to change all of it's API's & Models.
Now i have created a generic tier to handle the requests and apis and almost mid way into implementing all the services, now i came across this problem, the previous defined models are used widely around the application of course and since its MVC , Massive View Controller. it is going to cost me too much changing everything in each scene to the new model type,
therefore i thought of making an adapter to cast the new models when i get them in my
callback closure to the old ones type.
I have already figured out a way but the problem its pretty much long, long way i am looking for a better approach if existed and a better solution over all for the case if there was a better one.
protocol Parsable {
var time: String { get }
var span: String { get }
init(_ copy: Parsable)
}
class Foo: Parsable {
required init(_ copy: Parsable) {
self.span = copy.span
self.time = copy.time
}
init(time: String, span: String) {
self.time = time
self.span = span
}
var time = ""
var span = ""
}
class Fee: Parsable {
required init(_ copy: Parsable) {
self.span = copy.span
self.time = copy.time
}
init(time: String, span: String, date: String) {
self.time = time
self.span = span
self.date = date // an extra var that is not used in Foo
}
var time = ""
var span = ""
var date = ""
}
var foo = Foo(time: "", span: "")
var fee = Fee(time: "2", span: "ye", date: "123")
// Usage
var deeped = Foo(fee)
As you can tell from the code i've created a protocol that contains the variables and an init() that holds its type, now imagine this to implement a model with +50 variable and +40 model in total, might need an age or two.

I hope i understood the problem, It's not a clean solution but it's quick an flexible:
What about an additional method in the protocol with an implementation in it's extension to perform the all the copies? This is possible since i see that all the properties have an assigned dummy value. Then the only thing to do for each object implementing Parsable is to call such method in the initializer. kind of a commonInit() method.
protocol Parsable {
var time: String { get }
var span: String { get }
init(_ copy: Parsable)
func initParsableProperties(from copy: Parsable)
}
extension Parsable {
func initParsableProperties(from copy: Parsable) {
self.span = copy.span
self.time = copy.time
}
}
class Foo: Parsable {
...
required init(_ copy: Parsable) {
initParsableProperties(from: copy)
}
...
}
This also allows you to add additional properties in the initializers if needded. If you don't need additional properties it could then be directly implemented in the initializer, but it requires some more tricky solutions.

So i Achieved this using Codable, i have created a dummy protocol that is conforming to Codable, and using that in every class, struct that i needed to convert it, and created a generic function extended from that protocol, to encode the object to data then decode it into the new type desired,
With that i don't have to declare any variable or property i needed to copy manually.
check out the code below.
protocol Convertable: Codable {}
class Foo: Convertable {
var foo: String
var fee: String
init(foo: String, fee: String) {
self.foo = foo
self.fee = fee
}
}
class Fee: Convertable{
var fee: String
init( fee: String) {
self.fee = fee
}
}
//Generic function to convert
extension Convertable {
func convert<T: Codable>(_ primary: T.Type) -> T? {
return try? JSONDecoder().decode(primary, from: try! JSONEncoder().encode(self))
}
}
var foo = Foo(foo: "nothing", fee: "nothing")
let fee = foo.convert(Fee.self)
fee?.fee // nothing

Related

Generating auto-incrementing Instance IDs in Swift using Protocols and protocol-extensions only

Goal
To create an "AutoIDable" protocol with the following behaviour.
Every instance of a class conforming to this protocol will get an auto-generated "id" property of String type.
The code should generate id strings in the format <prefix><Instance-count-starting-from-1> (Eg: E-1, E-2, ...E-<n> and so on for 1st , 2nd ... nth Instance of the conforming class.
The protocol & protocol extensions should do ALL of the required work to generate the id strings. The conforming class will only have to subscribe to the protocol and nothing more.
Current status:
I have achieved Goal-1 & Goal-2 with the following implementation:
protocol Identifiable {
var id: String { get }
}
protocol AutoIDable: Identifiable{
static var _instanceCount: Int { get set }
}
class AutoID: AutoIDable {
init(idPrefix: String) {
setAutoID(prefix: idPrefix)
}
internal static var _instanceCount: Int = 0
var id: String = ""
func setAutoID(prefix: String = ""){
Self._instanceCount += 1
self.id = "\(prefix)\(Self._instanceCount)"
}
}
class Employee: AutoID {
init(){
super.init(idPrefix: "E-")
}
}
let e1 = Employee()
let e2 = Employee()
let e3 = Employee()
print(e1.id)
print(e2.id)
print(e3.id)
print(e1.id)
The output from running the above code:
E-1
E-2
E-3
E-1
Todo:
To achieve Goal-3, I need to eliminate the AutoID superclass and implement the same functionality using protocol extensions.
I ran into trouble because:
Protocol extensions do not allow static stored properties. I do know how to work around this limitation without using a superclass.
I do not know how to inject code into all the initialisers the creator of the Employee class might create. Again, I could not think of a workaround without using a superclass.
I would be grateful if you can point me in the right direction.
PS: New to Swift programming. If you’ve suggestions for implementing the code in a more “swifty” way, please do let me know. :-)
Since you want to use protocols, you can't have a stored property in the protocol. So, you'll need some place to store the incrementing ID value, if not the IDs themselves.
Not sure if it violates your requirements of using only protocols, because it would require a type for storage, but at least it won't require conforming classes to have a superclass.
So, let's say we build such a class that holds all the IDs and keeps the incrementing counter:
class AutoIncrementId {
static private var inc: Int = 0
static private var ids: [ObjectIdentifier: String] = [:]
static func getId(_ objectId: ObjectIdentifier, prefix: String) -> String {
if let id = ids[objectId] { return id }
else {
inc += 1
let id = "\(prefix)\(inc)"
ids[objectId] = id
return id
}
}
}
Then the protocol requirement could be:
protocol AutoIdentifiable {
static var prefix: String { get }
var id: String { get }
}
So, a class would need to define its prefix. But we could define a default implementation for id:
extension AutoIdentifiable where Self: AnyObject {
var id: String {
AutoIncrementId.getId(ObjectIdentifier(self), prefix: Self.prefix)
}
}
The usage would be:
class Employee: AutoIdentifiable {
static let prefix = "E-"
}
let e1 = Employee()
let e2 = Employee()
let e3 = Employee()
print(e1.id) // E-1
print(e2.id) // E-2
print(e3.id) // E-3
print(e1.id) // E-1

Multiple classes with the same generic properties and setup, how can I reduce duplicate code?

There are a lot of questions out there that are similar, but I'm having a hard time finding something that explains exactly what I'm looking for
I have multiple Services, which handle a generic Data type. They currently all subclass an semi-"abstract" class, DataService
This is because all of these Services have the same stored properties:
class DataService<T: Data> {
let id: String
let eventDataProviders: [EventDataProvider]
private let storedDataProviders: [StoredDataProvider]
and their init are the same as well:
init(id: String, eventDataProviders: [EventDataProvider], storedDataProviders: [StoredDataProvider]) {
self.id = id
self.storedDataProviders = storedDataProviders
self.eventDataProviders = eventDataProviders
self.setupStoredDataProviders()
self.setupEventDataProviders()
}
the setup methods are also the same
The difference between these classes is how they handle data, currently defined in an "abstract" function
func eventReceivedHandler() -> ((T) -> Void) {
fatalError("DataService does not have eventReceivedHandler defined")
}
Most resources recommend Protocols and Protocol Extensions.
Which I would prefer as well, but I think the two things that make that difficult are:
Trying to reduce duplicate code by keeping the stored property declarations in one place, and by sharing an init
The generic type on the class, it doesn't seem straight-forward to maintain that through a protocol
But the problem with this current solution is
The "abstract" class is exposed, when we don't want anybody to actually instantiate an instance
The eventReceivedHandler isn't compiler-enforced
Is there a correct solution here? I thought this architecture may be common enough, but I've really been struggling finding anything around online, my search queries contain too many overused terms
You can create a protocol that has eventReceivedHandler() method, i.e.
protocol EventHandler {
func eventReceivedHandler() -> ((Data)->())
}
Since you're defining T: Data, I don't think there is even a need for generic type T since always Data is expected in that place.
Now, you can create your class DataService as already did,
class DataService {
let id: String
let eventDataProviders: [EventDataProvider]
private let storedDataProviders: [StoredDataProvider]
init(id: String, eventDataProviders: [EventDataProvider], storedDataProviders: [StoredDataProvider]) {
//....
}
func setupStoredDataProviders() {
//.....
}
func setupEventDataProviders() {
//.....
}
}
Now, the Service classes will be created like,
class Service1: DataService, EventHandler {
func eventReceivedHandler() -> ((Data) -> ()) {
//....
}
}
class Service2: DataService, EventHandler {
func eventReceivedHandler() -> ((Data) -> ()) {
//....
}
}
In case you still have any doubts regarding that, you can ask.
You might want to use a protocol with an associated type :
protocol Service {
associatedtype T
var eventDataProviders: [EventDataProvider<T>] { get }
var storedDataProviders: [StoredDataProvider<T>] { get }
}
Coupled with generic providers classes :
class EventDataProvider<T> {
}
class StoredDataProvider<T> {
}
And a concrete class :
class DataService<T>: Service {
let id: String
let eventDataProviders: [EventDataProvider<T>]
let storedDataProviders: [StoredDataProvider<T>]
init(id: String, eventDataProviders: [EventDataProvider<T>], storedDataProviders: [StoredDataProvider<T>]) {
self.id = id
self.storedDataProviders = storedDataProviders
self.eventDataProviders = eventDataProviders
self.setupStoredDataProviders()
self.setupEventDataProviders()
}
func setupStoredDataProviders() {
}
func setupEventDataProviders() {
}
}
Would allow you to have DataService instances handling different types of data eg. :
let data = DataService<Data>(id: "1", eventDataProviders: [EventDataProvider<Data>()], storedDataProviders: [StoredDataProvider<Data>()])
let data2 = DataService<Int>(id: "2", eventDataProviders: [EventDataProvider<Int>()], storedDataProviders: [StoredDataProvider<Int>()])
And you would also gain more type safety as :
let data3 = DataService<Data>(id: "3", eventDataProviders: [EventDataProvider<Data>()], storedDataProviders: [StoredDataProvider<Int>()])
would trigger :
Cannot convert value of type '[EventDataProvider]' to expected
argument type '[EventDataProvider<_>]'
Unfortunately, you loose access control as storedDataProviders is no longer private.

In Swift, does a protocol extension allow function bodies?

I'm going through a tutorial and I noticed that the author extended their protocol called Activity and wrote the function's body in their code. This does compile however I was under the impression that protocols only show method signatures or if it does implement the body then it'll be a mutating function. The code below doesn't use mutating on one of its functions but it still runs and WORKS! Can someone explain the phenomena or confirm that protocol extensions can have method bodies?
import CareKit
import SwiftyJSON
enum ActivityType: String {
case Intervention
case Assessment
}
enum ScheduleType: String {
case Weekly
case Daily
}
enum StepFormat : String {
case Scale
case Quantity
}
protocol Activity {
var identifier : String { get set}
var groupIdentifier : String { get set}
var title : String { get set}
var colour : UIColor? { get set}
var text : String { get set}
var startDate : Date { get set}
var schedule : [NSNumber] { get set}
var scheduleType : ScheduleType { get set}
var instructions : String? { get set}
var imageURL : NSURL? { get set}
var activityType: ActivityType { get set}
var medication : Medication? { get set}
init()
init(json: JSON)
func createCareKitActivity() -> OCKCarePlanActivity
}
extension Activity {
// A mutating function to allow Acticities or Assessments to intialiser base properties
mutating func parseActivityFields(json: JSON) {
self.identifier = json["identifier"].string!
self.groupIdentifier = json["group_identifier"].string!
self.title = json["title"].string!
self.text = json["text"].string!
let colourString = json["color"].string!
self.colour = UIColor.colorWithString(colourString)
if let instructionString = json["instructions"].string {
self.instructions = instructionString
}
if let imageString = json["imageURL"].string {
let componentsOfString = imageString.components(separatedBy: ".")
if let pathForResource = Bundle.main.path(forResource: componentsOfString[0], ofType: componentsOfString[1]){
self.imageURL = NSURL(fileURLWithPath: pathForResource)
}
}
self.startDate = dateFromString(string: json["startdate"].string!)!
self.scheduleType = ScheduleType(rawValue: json["scheduletype"].string!)!
self.schedule = json["schedule"].string!.components(separatedBy: ",").map ( {
NSNumber(value: Int32($0)!)
})
if let medication = json["medication"].string,
let medicationImageString = json["medicationimage"].string {
let componentsOfString = medicationImageString.components(separatedBy: ".")
let pathForResource = Bundle.main.path(forResource: componentsOfString[0], ofType: componentsOfString[1])
self.medication = Medication.init(medication: medication, imageURL: NSURL.init(fileURLWithPath: pathForResource!))
}
}
init(json: JSON) {
self.init()
self.parseActivityFields(json: json)
}
func createCareKitActivity() -> OCKCarePlanActivity{
//creates a schedule based on the internal values for start and end dates
let startDateComponents = NSDateComponents(date: self.startDate, calendar: NSCalendar(calendarIdentifier: NSCalendar.Identifier.gregorian)! as Calendar)
let activitySchedule: OCKCareSchedule!
switch self.scheduleType {
case .Weekly :
activitySchedule = OCKCareSchedule.weeklySchedule(withStartDate: startDateComponents as DateComponents, occurrencesOnEachDay: self.schedule)
case .Daily:
activitySchedule = OCKCareSchedule.dailySchedule(withStartDate: startDateComponents as DateComponents, occurrencesPerDay: self.schedule[0].uintValue)
}
let activity = OCKCarePlanActivity.intervention(
withIdentifier: identifier,
groupIdentifier: nil,
title: title,
text: text,
tintColor: colour,
instructions: instructions,
imageURL: imageURL as? URL,
schedule: activitySchedule,
userInfo: ["medication": medication], optional: false)
return activity
}
}
In Swift, extensions allow you to provide default implementations for protocols.
According to the Swift documentation on Protocols,
Protocols can be extended to provide method, initializer, subscript,
and computed property implementations to conforming types. This allows
you to define behavior on protocols themselves, rather than in each
type’s individual conformance or in a global function.
Source: Swift Documentation
In Swift, does a protocol extension allow function bodies?
Yes. It's a really convenient way to add specific functionality only to instances of some protocol. Consider this:
protocol Flying {
func useWings()
}
extension Flying {
func fly() {}
}
class Animal {}
class Bird: Animal {}
extension Bird: Flying {
func useWings() {}
}
let bird = Bird()
bird.fly()
It also makes some logic here. If something can use wings, then it also probably can fly. So when we extend Bird to implement Flying as it has useWings - it also can fly now.
The code below doesn't use mutating on one of its functions but it still runs and WORKS! Can someone explain the phenomena
Mutating keyword says that function will mutate the value it's called onto. You have to say it explicitly if your protocol is not a class (protocol Some: class {}). The createCareKitActivity() doesn't mutate self, so you don't have to specify mutating
Class -> Protocol -> Extension
Swift's protocol extension allows your class operates by additional or default functions

Enforce model unicity - Swift solution?

What is a good approach to ensure that a model representing an element identified by an id doesn't get instantiated twice? Are there some good libraries to do that in Swift? I could not find anything even though I suspect this to be a common problem.
I'd like something like this to happen:
let a = fetchElementWithId(123)
let b = fetchElementWithId(123)
// then a === b
I thought of doing something like
class Weak<T: AnyObject> {
weak var value : T?
init(value: T) {
self.value = value
}
}
class Foo {
private static var cache = [String: Weak<Foo>]()
var id: String
var bar: String
static func initialize(id: String, bar: String) -> Foo {
if let weakExistingModel = Foo.cache[id], let existingModel = weakExistingModel.value {
existingModel.bar = bar
return existingModel
}
return Foo(id: id, bar: bar)
}
private init(id: String, bar: String) {
self.id = id
self.bar = bar
Foo.cache[id] = Weak(value: self)
}
deinit() {
Foo.removeValueForKey(id)
}
}
And then call the static initializer instead of the normal one. But things can get messy if I start to get subclasses that represent the same document etc.
So before I dig into this, I'm wondering what smart people have done about it before! I guess the solution is not particularly swift related (even though for instance in swift you can't override static functions, which could be an issue), but since I'm using swift I'm more interested in a libraries in that language.

Mapping in Swift Between Protocol Conforming Types

I want to map between any two objects which conform to the same protocol. It would be convenient to do so via a function with the signature:
func mapFrom<T>(objectA: T, to inout objectB: T)
Even better though (for immutable types) would be to have it in the form:
func map<T, U: T>(from source: T) -> U
where somehow it could initialize a U object from the values in T.
I would like to do this via Swift Reflection rather than using the Objective-C run-time, but I would settle for that if it was the only way. If somehow it could be done without reflection that would be amazing, but I don't see how.
The reason I want to do this is because I have mutable Realm classes which conform to their respective protocol, and I want to map them to the immutable struct types.
An example would be:
/**
The protocol.
*/
protocol Food {
var name: String { get }
var weight: Float { get }
var price: Float { get }
}
/**
The mutable Realm class representation.
*/
final class FoodEntity: Object, Food {
dynamic var name = ""
dynamic var weight = 0.0
dynamic var price = 0.0
}
/**
The final struct I want to map to from the Realm representation.
*/
struct FoodProduct: Food {
let name: String
let weight: Float
let price: Float
}
I would like to be able to have a generic function or method with which to map a FoodEntity to a FoodProduct without having to manually do something like:
FoodProduct(name: entity.name, weight: entity.weight, price: entity.price)
How can this be done, if it can be done at all?
I think you are looking for something like this.
func fetchAllFoodProducts() -> [FoodProduct]
{
var foodProducts : [FoodProduct] = []
// Fetch From Realm
let products = realm.objects(FoodEntity.self)
for product in products
{
foodProducts.append(FoodProduct(name: product.name, weight: product.weight, price: product.price))
}
return foodProducts
}
The thing is that there can't be a generic way to do this. Because you have to assign the values of name, weight & price somehow. This is the closest you can get, I think.
Or you can do something like this.
func fetchAllFoodProducts() -> [FoodProduct]
{
var foodProducts : [FoodProduct] = []
// Fetch From Realm
let products = realm.objects(FoodEntity.self)
for product in products
{
foodProducts.append(FoodProduct(entity: product))
}
return foodProducts
}
By altering your FoodEntity a little.
struct FoodProduct: Food {
let name: String
let weight: Float
let price: Float
init(entity : FoodEntity)
{
self.name = entity.name
self.weight = entity.weight
self.price = entity.price
}
}