Initialising properties in a subclass? - ios

I have a subclass of a subclass as i require a variation on a varients behaviour based on a base class.
The issue im facing is that this new subclass requires some custom values that need to be initialised in an init method.
The situation is:
I have a value e.g. let time: Dynamic<String?> where I have to use let due to the binding method
and so i need to provide a value in an init in order to compile...
but as the class signature looks like this: class NewViewModel: DurationViewModel<Model>
the superclass is also class DurationViewModel<T: Model>: BaseViewModel<T>
I dont seem to be able to use convenience init or init with a call to super
Is there a correct way to achieve this so i can initialise these let constants in this subclass

I'm not sure I understand. Does this not work for you?
class Parent {
let someVar: String
init() {
someVar = "Some value"
}
}
class Child: Parent {
let someOtherVar: String
override init() {
someOtherVar = "Some other value"
super.init()
}
}

Related

Swift init(), defining custom init is it overriding?

I have some confusion over this:
class Person {
var name: String
var age: Int
init(){
name = “Tim”
age = 30
}
}
A basic custom init. What exactly is the code below doing?:
init(){
//Code here
}
It's not an override because we don't use override func init(). Someone said it's actually calling a default init method that comes with the class. If that's the case then what do the curly brackets do?
Because you haven't subclassed from NSObject, there is no init() method to override. Hence why you don't need it in this case.
In this case, nothing else is called when you call your init() method, there are no other default initializers. The curly brackets are there simply because you're not accepting any arguments to your init method. You could for example accept some arguments:
init(withName name: String, andAge age: Int) {
self.name = name
self.age = age
}
And call it like so:
Person(withName: "Chris", andAge: 23)
Swift provides a default initializer for any structure or class that provides default values for all of its properties and does not provide at least one initializer itself. The default initializer simply creates a new instance with all of its properties set to their default values.
You can customize the initialization process with input parameters and optional property types, or by assigning constant properties during initialization.
You can provide initialization parameters as part of an initializer’s definition, to define the types and names of values that customize the initialization process. Initialization parameters have the same capabilities and syntax as function and method parameters.

Trouble mocking singleton for unit testing in Swift

Hello I am trying to mock one of the singletons I use to test that various view controllers actually call properly it's methods.
I have the singleton declared as such
public class ModelsManager {
static let sharedInstance = ModelsManager()
private init() {}
[...]
}
In the view controllers that use the singleton, it is set to a lazy computed property as such:
class MyViewController: UIViewController {
lazy var Models = {
return ModelsManager.sharedInstance
}()
[...]
}
I am trying to mock the ModelsManager singleton in my XCTestCase as such:
[...]
func testSomething() {
let vc = MyViewController(nibName: "MyView", bundle: nil)
var mockModelsManager = ModelsManagerMock.sharedInstance
vc.Models = mockModelsManager
[... do something that calls a function in ModelsManager...]
expect(mockModelsManager.flag) == true // Using Nimble here
}
class ModelsManagerMock: ModelsManager {
var flag = false
override func test() {
flag = true
}
}
In the expect() assertion I am getting Value of type 'ModelsManager' has no member 'flag'
What am I missing here?
EDIT
It appears that what I was missing was ModelsManagerMock.sharedInstance still returns IRModelsManager() from the superclass. Due to the fact that static can't be overwritten by subclasses, how do I get around this?
The correct solution must involve not subclassing your singleton. Creating a singleton with a private init method prohibits you from subclassing this method.
If the goal is to test the current functionality of the singleton, why do you want to add additional functionality to it? The key point of a singleton is that there should only ever be one. If you want to support more than one, you shouldn't make it a singleton, even if it's just for testing.

In swift, how to refer to topmost class when my class has subclass of same name

In Swift:
How can I assign a topmost myObject to the innerObj variable?
Does swift have some sort of namespace operator that lets me create an myObject from global namespace?
Consider the code below.
//my object that can init with a message=string
class MyObject {
init(message: String) {
println(message)
}
}
//here I define a global works fine
let global = myObject(message: "this works")
//other class
class ViewController: UIViewController {
//defines an inner class with same name
class MyObject {
func failsFunction(){
//cannot invoke initializer for type "ViewController.myObject" with an argument of type (String)
let innerObj = myObject("how can I refer to the topmost myObject here?")
}
}
}
My first answer would be "don't do that." It's technically legal because the two classes have unique scope, but it's confusing as all hell, and will come back to bite you 6 months from now when you are coming back to this code and don't remember that you have a global class and a child class of ViewController with the same name.
If you are going to ignore that advice, Lou provided your solution: Create a typeAlias at the top level and use that inside your ViewController class so that you can reference the global class inside ViewController.
Secondly, class names should start with an upper-case letter. So class myObject should be class MyObject. This is a documented convention of the language.
Thirdly, myObject is a dreadful name for a class. It doesn't give you any idea what the class is for. Even if this is a learning exercise, you should still follow good coding practices. It trains good habits, and test code has a way of finding itself in real projects, or posted as demo code somewhere, or whatever.
You need to alias it before you hide it with:
typealias GlobalMyObject = MyObject
One usual way is to bind your outer class into struct. This pattern is quite similar to creating a namespace. You could do it like this
struct MyNameSpace {
class myObject {
init(message: String) {
print(message)
}
}
}
//here I define a global works fine
let global = MyNameSpace.myObject(message: "this works")
//other class
class ViewController: UIViewController {
//defines a subclass with same name
class myObject {
func failsFunction(){
//cannot invoke initializer for type "ViewController.myObject" with an argument of type (String)
let innerObj = MyNameSpace.myObject(message: "how can I refer to the topmost myObject here?")
}
}
}
Then, you could use both the classes and the compiler determines the use cases differently for both.

Add weak reference to assigned Closure in Swift?

I have the following closure:
class BISSettingController : XLFormViewController {
class func initializeForm() -> XLFormDescriptor {
var form : XLFormDescriptor
var section : XLFormSectionDescriptor
var row : XLFormRowDescriptor
form = XLFormDescriptor()
row = XLFormRowDescriptor(tag: "tag", rowType: XLFormRowDescriptorTypeButton, title: "Title")
row.action.formBlock = {[weak self](sender: XLFormRowDescriptor!) -> Void in
self?.deselectFormRow(sender)
...
}
}
}
I want to use self as weak reference inside the closure. But when I build the code I get the following error:
'weak' cannot be applied to non-class type 'BISSettingController.Type'
How can I solve this to make it work?
The problem is that this is a class method (class func). In a class method, self means the class. There is no need for memory management on a self representing the class; the class cannot "leak", because it persists for the life of the app anyway. Thus, you cannot describe a reference to a class as weak.
Based on the error message you're getting, it sounds like self is not an object, so you don't need the access list at all.
Can you post more information on the object that contains this code?
EDIT:
Looking at your updated question, it seems that the code you're using is in a class method, not an instance method. That code doesn't seem to make sense from a a class method however.

Subclassing NSObject in Swift - Best Practice with Initializers

Here is the layout of an example Class, can someone guide me on what's best practice when creating a subclass of NSObject?
class MyClass: NSObject {
var someProperty: NSString! = nil
override init() {
self.someProperty = "John"
super.init()
}
init(fromString string: NSString) {
self.someProperty = string
super.init()
}
}
Is this correct, am I following best practice here?
I wonder if I'm correctly setting up the initializers (one that sets the string to a default, and one which I can pass in a string)?
Should I call super.init() at the end of each of the initializers?
Should my more specific (the one that takes a string) initializer simply call self.init() at the end rather than super.init()?
What is the right way to set up the initializers in Swift when subclassing NSObject? - and how should I call the super init ?
This question (albeit in Objective C) suggests you should have an init, which you always call and simply set the properties in more specific inits: Objective-C Multiple Initialisers
I'm not Swift ninja but I would write MyClass as:
class MyClass: NSObject {
var someProperty: NSString // no need (!). It will be initialised from controller
init(fromString string: NSString) {
self.someProperty = string
super.init() // can actually be omitted in this example because will happen automatically.
}
convenience override init() {
self.init(fromString:"John") // calls above mentioned controller with default name
}
}
See the initialization section of the documentation
If someProperty can be nil, then I think you want to define the property as:
var someProperty: NSString?
This also eliminates the need for a custom initializer (at least, for this property), since the property doesn't require a value at initialization time.
In complement to the answers, a good idea is to call super.init() before other statements. I think it's a stronger requirement in Swift because allocations are implicit.

Resources