Swift superclass/subclass view controller variables - ios

I have a superclass UIViewController that contains this:
var results: [AnyObject] = []
I also have other methods in the superclass that's based on the content of results array.
I then have subclasses that inherit from this superclass, by loading data from REST API to populate results array with various types of data.
I currently don't override results array in subclass' viewDidLoad() or any other method. I simply clear the array using results = [] and then load the array with a specific class type, such as a custom class Product or String.
results.append(Product())
I've been intermittenly getting crashes, but I can't tell why. I suspect it's due to the way the inheritance is working. Am I doing this correctly? Should I be overriding results in an init() method of the subclass or using `override var?

I think typecasting can work here.
Try to do this in your subclasses:
class SubClass: SuperClass {
private var _results: [Product] = []
override var results: [AnyObject] {
get {
return _results
}
set {
_results = newValue as! [Product]
}
}
}
But Product must be a class and not struct or enum.
Also as String does not conform to AnyObject you cannot save Strings in results array.

Related

Handling RLMResult in heterogeneous table view

How should I handle a table view whose cells represent both a RLMResult and other custom views?
Say I have this structure, a todo list app that shows items of todo list and some ads:
protocol TableItem {}
class ToDoItem: RLMObject, TableItem {
// properties
}
class Advertising: TableItem {
// properties
}
class ViewController: UIViewController {
var result: RLMResult<ToDoItem>
var ads: [Advertising]
var tableViewItems: [TableItem] // Created by mixing both `result` and `ads`.
}
// other class stuff
I have to dequeue a different cell based on the the type of each item in tableViewItems.
The simplest thing would be to convert the result property to a simple Array<ToDoItem> and then concatenate both arrays; Realm documentation discourages to convert a RLMResult to a simple array to avoid losing all lazy features of RLMResult.
Any idea?

Swift - Initializing model object with properties across multiple views

A client wants me to initialize a model object, but the issue I'm facing is that the properties I need are located across five view controllers. At view controller 1 I define propertyA for my object. View controller 2 I define propertyB, and so on. On the final view I get to see a summary of what i've chosen and from there I can finally create my object.
I'm doing this incredibly long and inefficient at the moment where I have the same optional variables for each property across many views. Any help would be great.
For this scenario you should try Singleton pattern
Create class having all properties and create its singleton also:
public class Property {
public var propertyA:AnyObject? /// define your appropriate data type
public var propertyB:AnyObject?
public var propertyC:AnyObject?
public var propertyD:AnyObject?
public var propertyE:AnyObject?
static let sharedInstance = Property()
}
To Set Values in different-2 view controller follow below pattern. Here I am assuming that you can set property any place in view controller. For now I am considering to viewDidLoad you can change value to any part of view controller
class ViewController1: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
Property.sharedInstance.propertyA = "X" as AnyObject //// Value should be of same data type of propertyA
}
}
class ViewController2: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
Property.sharedInstance.propertyB = "Y" as AnyObject //// Value should be of same data type of propertyA
}
}
etc
finally at the end you will get values of all assigned parameters
print(Property.sharedInstance.propertyA)
print(Property.sharedInstance.propertyB)
print(Property.sharedInstance.propertyC)
print(Property.sharedInstance.propertyD)
print(Property.sharedInstance.propertyE)

how to make a deep copy of a swift array of class objects

So I know that swift array is implemented as struct, and it will do automatically copy by itself.
I have write my class MyClass and I have implemented copyWithZone to make copy of it
However, my swift array contains my MyClass objects, like:
var array = [MyClass]()
when I wan to make a copy of that array like
var anotherArray = array
It still does not call MyClassObject.copyWithZone, and later if I change the object property in array, anotherArray will also reflect the change.
How can I make a copy of that without writing a for loop to iterate every object?
It's not duplicated as deep copy for array of objects in swift because I cannot use struct to rewrite my class.
As a simple statement, you could use code like this:
var copiedArray = array.map{$0.copy()}
Note that the term "deepCopy" is a little misleading for what you're talking about. What if the array is heterogeneous and contains other containers like arrays, dictionaries, sets, and other custom container and "leaf" objects? What you should really do is to create a protocol DeepCopiable and make it a requirement that any object that conforms to DeepCopiable require that any child objects also conform to the DeepCopiable protocol, and write the deepCopy() method to recursively call deepCopy() on all child objects. That way you wind up with a deep copy that works at any arbitrary depth.
If Element of an array is of reference type, conform that Element with NSCopying and implement copyWithZone method.
class Book {
var name: String
init(_ name: String) {
self.name = name
}
}
extension Book: NSCopying {
func copy(with zone: NSZone? = nil) -> Any {
return Book(name)
}
}
Now implement an array extension to make a deep copy
extension Array where Element: NSCopying {
func copy() -> [Element] {
return self.map { $0.copy() as! Element }
}
}
Test the code base
let b1 = Book("Book1")
let b2 = Book("Book2")
let list = [b1, b2]
let clonedList = list.copy()
clonedList is now copy of list and won't affect each-other if you make change to any of two.
Thanks Duncan for your solution, here is an extension using it.
Note that your class must adopt the NSCopying protocol. For how to do that see here https://www.hackingwithswift.com/example-code/system/how-to-copy-objects-in-swift-using-copy
extension Array {
func copiedElements() -> Array<Element> {
return self.map{
let copiable = $0 as! NSCopying
return copiable.copy() as! Element
}
}
}

Save array of images with Realm in swift

okay, i have an app with 3 view controllers and in 2 of them i have 5 arrays of images. what i want to do is save each array of images using realm. the arrays are mutable and the user adds the images to the array of their choosing in vc1 and can send them to the arrays in vc2, but im not sure if i can just replace (in vc1)
this:
var array: [UIImage] = [] {
didSet{
cView1.reloadData()
}
}
with This:
dynamic var array: [UIImage] = [] {
didSet{
cView1.reloadData()
}
}
i am also getting this error when i try to inherit RLMObject.
"multiple inheritance from classes uiviewcontroller and RLMObject"
here is my code
class CViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate, UICollectionViewDelegate, UICollectionViewDataSource, CDelegate , RLMObject
im fairly new to ios developing so any little bit helps thanks in advance
The best approach is to save file path in DB, not image itself. So you need to create array of image paths instead array of images. Like this: let images = List<String>()
Also according to Realm Docs 'List' can't be dynamic:
When added as a property on Object models, the property must be declared as let and cannot be dynamic.
And final, you must to inherit from 'Object', not 'RLMObject' and Realm class must be separate, like in this official example:
class Dog: Object {
dynamic var name: String = ""
dynamic var adopted: Bool = false
let siblings = List<Dog>()
}

Override [AnyObject]? array in parent class in Swift

I have a ParentController and ChildController as below. The ParentController holds an array of [AnyObject]? and the child class holds an array of specific models (i.e. Merchant). The parent class has methods that references the results array, hence I've declared it as [AnyObject]?.
Is there a way that I can override the results array in ChildController?
Rationale: I had tried results.append() originally in ChildController, but apparently that causes issues due to downcasting. The problem was sporadic, so hard to explain. However, after about a week of research and trial & error, I think the only way to solve this is to create a separate array in the ChildController to hold data, but still be accessible by methods in the parent class. Thoughts?
class ParentClass: UIViewController {
var results: [AnyObject]?
//has methods that reference results array
}
class ChildClass: ParentClass {
var merchants: [Merchant]?
override var results: [AnyObject]? {
get {
return self.merchants as [AnyObject]?
//this doesn't work, gives EXC_BAD_ACCESS error
}
set {
super.results = self.merchants as [AnyObject]?
}
}
}

Resources