Function accepting generic parameters - swift

I have a subclass of NSManagedObject. I'm using a protocol to create a "wrapper" class. In my controller the data can be either: Items or Item1. To be able to use my function I'll have to add the protocol ItemInfo to Items but that means I'll have to add
var items: Items { return self }
in Items, which seems a bit redundant. I've tried creating a base class but that didn't work.
Question:
Is there a better way to let my function accept both Items and Item1 as parameter like using generics?
NSManagedObject:
class Items: NSManagedObject {
#NSManaged var name: String
#NSManaged var code: String
}
Protocol:
protocol ItemInfo {
var item: Items { get }
}
extension ItemInfo {
var name : String { return item.name }
var code : String { return item.code }
}
Wrapper:
class Item1: ItemInfo {
let item: Items
init(item: Items) { self.item = item }
}
function:
func handleItem(item: ItemInfo) {
print(item.name)
print(item.code)
}
I could use:
func handleItem<T>(item: T) {
if let a = item as? Items {
print(a.name)
print(a.code)
}
if let a = item as? ItemInfo {
print(a.name)
print(a.code)
}
}
But this doesn't seem the right way ...

If I understand correctly what you are trying to achieve (function accepting two kind of items), I would use protocol as type accepted by function, refer the code below
class Items: NSManagedObject, ItemInfo {
#NSManaged var name: String
#NSManaged var code: String
}
class Item1: NSManagedObject, ItemInfo {
#NSManaged var name: String
#NSManaged var code: String
}
protocol ItemInfo {
var name: String {get set}
var code: String {get set}
}
and function would look like this
func handle(item: ItemInfo) {
print(item.code)
print(item.name)
}

Related

How to map model for NSManagedObject?

When I try to do this, the model is stored in the NSManagedObjectContext if I use the context, and without it it throws an error, but I'm not expecting the same result.
Is there an easy way to implement this?
class WordDal: NSManagedObject {
#nonobjc public class func fetchRequest() -> NSFetchRequest<WordDal> {
return NSFetchRequest<WordDal>(entityName: "WordDal")
}
#NSManaged public var word: String?
#NSManaged public var uuid: UUID?
}
struct WordPresentation {
let word: String
let uuid: UUID
}
func mappingNSManagedObject(_ wordPresentation: WordPresentation) -> WordDal {
let model = WordDal()
model.uuid = wordPresentation.uuid
model.word = wordPresentation.word
return model
}
Consider to redesign your model to have computed property for the new wrapper type that transforms the property value to and from the wrapper value.
Implementing a computed property in a Swift Core Data model is often a clear, more intuitive way to achieve what you need.
Here is an example implementation:
struct WordPresentation {
let word: String
let uuid: UUID }
class WordDal: NSManagedObject {
#nonobjc public class func fetchRequest() -> NSFetchRequest<WordDal> {
return NSFetchRequest<WordDal>(entityName: "WordDal")
}
#NSManaged public var word: String?
#NSManaged public var uuid: UUID?
var wordPresentation : WordPresentation {
get {
return WordPresentation(word: self.word, uuid: self.uuid)
}
set {
self.word = newValue.name
self.uuid = newValue.id
}
}
}
I solved the problem like this (I don't know why I put it off and didn't understand right away):
class WordDal: NSManagedObject {
#nonobjc public class func fetchRequest() -> NSFetchRequest<WordDal> {
return NSFetchRequest<WordDal>(entityName: "WordDal")
}
#NSManaged public var word: String?
#NSManaged public var uuid: UUID?
}
struct WordPresentation {
let word: String
let uuid: UUID
}
func removeFromStorage(by uuid: UUID) {
getDataFromStorage { [weak self] objects in
guard let self = self else { return }
if let objectForRemove = objects.first(where: { $0.uuid == uuid }) {
self.coreDataStack.mainContext.delete(objectForRemove)
self.coreDataStack.saveContext(self.managedObjectContext)
}
}
}
I'm creating a presentation level model with UUID!
And I delete only on him himself UUID.
Now I can walk both ways.

Manage single variable for two different types of data

I have two UI of listing, the cells are the same in both listing. For both UI, the different Codable array is managed. i.e.
FirstViewController contains FirstDataModel & SecondViewController contains SecondDataModel.
So in FirstViewController, in cellForRow method I have called the code :
func setPastCell(cell:WeekCell, data_dic:FirstDataModel) {
cell.lblGoalA.text = predictScore1
cell.lblGoalB.text = predictScore2
}
Arrays:
struct FirstDataModel: Codable {
var team1_name:String?
var team2_name:String?
var status:Int?
var image:String?
var score:Int?
}
struct SecondDataModel: Codable {
var team1_name:String?
var team2_name:String?
var status:Int?
var image:String?
var count:Int?
var balance:Int?
}
I want to make common function for both FirstDataModel & SecondDataModel. So how can I manage it using generic function?
How can I pass FirstDataModel or SecondDataModel in setPastCell(cell: WeekCell, data_dic: FirstDataModel) ?
Thanks in advance!
You can inherit the two DataModel from a Protocol, and use Protocol properties in setup.
Example:
protocol ModelProtocol {
var descriptionOne: String { get }
var descriptionTwo: String { get }
}
struct FirstDataModel: ModelProtocol {}
func setPastCell(cell:WeekCell, data_dic: ModelProtocol) {
cell.lblGoalA.text = descriptionOne
cell.lblGoalB.text = descriptionTwo
}
Craete a protocol with common properties
protocol DataModel {
var team1_name:String? { get }
var team2_name:String? { get }
var status:Int? { get }
var image:String? { get }
}
Confirm to the protocol in your structs and add its properties
struct FirstDataModel: DataModel, Codable {
//Protocol properties
var team1_name:String?
var team2_name:String?
var status:Int?
var image:String?
//additional properties
var score:Int?
}
struct SecondDataModel: DataModel, Codable {
//Protocol properties
var team1_name:String?
var team2_name:String?
var status:Int?
var image:String?
//additional properties
var count:Int?
var balance:Int?
}
As both structs confirm to the DataModel protocol, you can use it in the function parameter.
func setPastCell<T: DataModel>(cell:WeekCell, data_dic:T) {
if let firstModel = data_dic as? FirstDataModel {
print(firstModel.team1_name)
print(firstModel.team2_name)
print(firstModel.status)
print(firstModel.image)
print(firstModel.score)
} else if let secondModel = data_dic as? SecondDataModel {
print(secondModel.team1_name)
print(secondModel.team2_name)
print(secondModel.status)
print(secondModel.image)
print(secondModel.count)
print(secondModel.balance)
}
}

How I can access to one Struct property that implements two protocols?

Im just learning Swift 4 and I have some troubles trying to access a property of an struct that have to implement 2 protocols
here is my struct
struct FigureA {
static func load() -> Model {
return Model.make(
name: "FigureName",
status: "Painted",
image: UIImage(named: "FigureA"),
description: "Good figure")
}
}
here the protocol 1
protocol ListModel: class {
var name: String { get }
var status: String { get }
var image: UIImage? { get }
}
here the protocol 2
protocol DetailModel: ListModel {
var categoryName: String { get }
var modelDescription: String? { get }
}
And I want to get the access to the description of the Struct but I don't know how at all.
Can someone give me a bit of light.
Here is good start for you:
protocol BaseProtocol {
var id: Int { get set }
}
protocol PersonProtocol: BaseProtocol {
var firstName: String { get set }
var lastName: String { get set }
var name: String { get }
}
struct Person: PersonProtocol {
var id: Int
var firstName: String
var lastName: String
var name: String { return firstName + " " + lastName }
}
//≠≠≠≠≠≠≠≠≠≠≠≠≠≠≠≠≠≠≠≠≠≠≠≠≠≠≠≠≠≠≠≠≠≠≠≠≠≠≠≠≠
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
//Create Struct Instance & Print properties.
let person = Person(id: 1001, firstName: "Manish", lastName: "Rathi")
print(person.id)
print(person.firstName)
print(person.lastName)
print(person.name)
}
}
#HappyCoding 😊

Swift override generic swift

I am trying to implement generic for MVVM Swift. I have two base class, an protocol for generic class. The special in here is inheritance. I tried for three hour but I can't fix it :(.
protocol ObjectProtocol {
var id: Int { get set }
var name: String { get set }
}
class BaseViewModel<T: ObjectProtocol> {
var objects: [T] = []
init(){
}
}
protocol ListViewControllerType {
associatedtype T: ObjectProtocol
associatedtype ViewModelType: BaseViewModel<T>
var viewModel: ViewModelType! { get set }
func showError(error: String)
}
extension ListViewControllerType {
func showError(error: String) {
print(error)
}
}
class Consult: ObjectProtocol {
var id: Int = 1
var name: String = "Consult"
}
class ConsultViewModel<T: Consult>: BaseViewModel<Consult> {
}
class ConsultViewController: ListViewControllerType {
var viewModel: ConsultViewModel<Consult>!
}
But I get error in var viewModel: ConsultViewModel<Consult>!
This is error: Type 'ConsultViewController' does not conform to protocol 'ListViewControllerType'
Someone have experience with generic and inheritance can help me please.
Thank you so much.
I usually do like this:
class BaseViewModel {
}
class TemplateViewModel<T: ObjectProtocol>: BaseViewModel {
var objects: [T] = []
init(){
}
}

Optional Variables in protocol is possible?

protocol AProtocol: BProtocol {
/// content to be shown on disclaimer Label of cell
var disclaimer: String {get set}
var cellDisclaimerAttributed: NSAttributedString {get}
var showSelection: Bool {get set}
var isReadMore: Bool {get}
}
I want to make variables optional so that I need not implement all variables every time after conforming protocol. Like in Objective-C we did for methods:
protocol AProtocol: BProtocol {
/// content to be shown on disclaimer Label of cell
optional var disclaimer: String {get set}
optional var cellDisclaimerAttributed: NSAttributedString {get}
optional var showSelection: Bool {get set}
optional var isReadMore: Bool {get}
}
Is it possible?
protocol TestProtocol {
var name : String {set get}
var age : Int {set get}
}
Provide a default extension for the protocol. Provide the default implementation for all the variables set and get which u want them to be optional.
In below protocol, name and age are optional.
extension TestProtocol {
var name: String {
get { return "Any default Name" } set {}
}
var age : Int { get{ return 23 } set{} }
}
Now if I am conforming above protocol to any other class, like
class TestViewController: UIViewController, TestProtocol{
var itemName: String = ""
**I can implement the name only, and my objective is achieved here, that the controller will not give a warning that "TestViewController does not conform to protocol TestProtocol"**
var name: String {
get {
return itemName ?? ""
} set {}
}
}
If you want to conform to Swift's documentation, you'd have to implement it like this :
#objc protocol Named {
// variables
var name: String { get }
#objc optional var age: Int { get }
// methods
func addTen(to number: Int) -> Int
#objc optional func addTwenty(to number: Int) -> Int
}
class Person: Named {
var name: String
init(name: String) {
self.name = name
}
func addTen(to number: Int) -> Int {
return number + 10
}
}