According to Apple documentation initialize() method Initializes the class before it receives its first message.
Can somebody explain why initialize() is not working in Release build configuration?
For example:
class Test: NSObject {
override class func initialize() {
print("initialize")
}
class func test() {
print("test")
}
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
Test.test()
}
}
Output in Debug configuration:
initialize
test
Output in Release configuration:
test
I did a quick test and it looks like in Release configuration + initialize is not called unless you create an instance of the class. However in Debug calling a class method is enough to trigger +initialize. Looks like an undocumented caveat.
Edit:
Even more interesting fact is that for Objective-C project in both Debug and Release configurations calling a class method is enough to trigger + initialize. I would say this is a bug. You might want to file a radar for it.
Related
I have a weird crash that I managed to reproduce in skeleton app.
I have a framework which uses RxSwift az a cocoapod dependency.
It has a simple class defined:
public final class FWSupplier {
public let psubject = PublishSubject<Int>()
public let bsubject = BehaviorSubject<Int>(value: 0)
public init() { }
public func triggerBehaviour() {
self.bsubject.onNext(1)
}
public func triggerPublish() {
self.psubject.onNext(1)
}
}
I build the framework as an XCFramework and import it into a host app.
In the app I simply instantiate the FWSupplier in a view controller and call triggerPublish and it crashes.
class ViewController: UIViewController {
#IBOutlet var label: UILabel!
let supplier = FWSupplier()
override func viewDidLoad() {
super.viewDidLoad()
supplier.triggerPublish()
}
}
Anyone have any idea what I'm doing wrong?
Screenshot of error
Screenshot of stack
Do not mix release and debug. When you build XCFramework, it depends on the release version rxswift. When you build the host app, it uses the debug version rxswift. There is some #if Debug in the rxswift source code,mixing release and debug may cause a crash. Instead, you should build the release version rxswift framework and add it to the podspec.vendored_frameworks.
Consider the following example:
open class A { // This class is from the SDK and cannot be modified in anyway.
open func aFunc() {}
}
This below is my own class and I need the class to be open for others to override. But the method should NOT be available for overriding.
open class B : A { // This has to be open for others to override.
override open func aFunc() {} // I need to make this **final** somehow so the subclasses cannot override this.
}
Is it possible to mark the aFunc() method in class B final?
I tried adding final keyword, but there's a compiler error saying
Instance method cannot be declared both 'final' and 'open'
If I remove the open keyword, there's a compiler error saying
Overriding instance method must be as accessible as the declaration it
overrides
You can do this by making the method public like this:
open class A { // This class is from the SDK and cannot be modified in anyway.
open func aFunc() {}
}
open class B : A { // This has to be open for others to override.
override final public func aFunc() {}
}
open keyword is for letting subclasses from different module to override, whereas the public keyword only gives access to different module and do not allow the overriding. If you want to override this method in only your module and not in other modules you can just make it public without final.
I am taking a iOS course online provided by a famous university. I don't understand why the following code use override and it is legal.
According to the official definition, we use override to override superclass' methods. Where is the subclass and superclass in the following code?
What's been override and by what?
public override var description: String {
return "\(url.absoluteString) (aspect ratio = \(aspectRatio))"
}
Here is an example:
Your original class:
class Person {
func walk() {
//do something
}
}
Your subclass:
class Runner: Person {
override func walk() {
//do something that is different from Person's walk
}
}
In the Runner class, there is an override with the function walk. That is because it is a subclass of Person, and it can override Person's walk function. So If you instantiate a Runner:
var usainBolt = Runner()
And you call the walk function:
usainBolt.walk()
Then that will call the overriden function that you wrote in the Runner class. If you don't override it, it will call the walk function that you wrote in Person.
According to the official definition, we use override to override superclass' methods.
That's correct. The superclass in your example is the class that encloses the override of description property. This could be NSObject, some other class derived from it (directly or indirectly), or some class unrelated to NSObject that has var description: String property.
description is a property that Swift classes commonly have as a way to present themselves as a string, because description provides conformance to CustomStringConvertible protocol. This is similar to toString() method of Java, and to str() method of Python.
What's been override and by what?
The implementation of the property is what's being overridden. The class that has the implementation does the overriding.
I'm a bit confused with the new UI Unit Testing scheme that apple released in their XCode7 Beta. I think it's an awesome idea, but I have a couple questions.
this is one testing method I have...
func testMetricsProperties() {
// Used some of the metrics for testing for reference
let app = XCUIApplication()
app.scrollViews.descendantsMatchingType(.Unknown).containingType(.StaticText, identifier:"rim").childrenMatchingType(.Button).element.tap()
app.textFields["_XCUI:Secure"].typeText("")
app.typeText("\r")
app.buttons["dash metrics"].tap()
let element = app.descendantsMatchingType(.Unknown).containingType(.Image, identifier:"darkBackground.png").childrenMatchingType(.Unknown).element.childrenMatchingType(.Unknown).elementBoundByIndex(1).childrenMatchingType(.Unknown).element.childrenMatchingType(.Unknown).element
let offPlanRevenue = element.childrenMatchingType(.Unknown).elementBoundByIndex(0).staticTexts["OFF PLAN REVENUE"]
offPlanRevenue.tap()
XCTAssert(offPlanRevenue.exists);
XCTAssertEqual(offPlanRevenue.value as! String, "");
}
However, in the next testing method, it seems that I have to load the entire app again,
let app = XCUIApplication()
app.scrollViews.descendantsMatchingType(.Unknown).containingType(.StaticText, identifier:"im").childrenMatchingType(.Button).element.tap()
app.textFields["_XCUI:Secure"].typeText("")
app.typeText("\r")
app.buttons["dash metrics"].tap()
}
Is there anyway I can avoid this? This can be troublesome if i'm trying to run a full test on an entire suite.
I believe what you are looking for is using the setUp() and tearDown() methods. setUp() gets called before each test method and tearDown() gets called after each test method for a class.
override func setUp() {
super.setUp()
// Put setup code here. This method is called before the invocation of each test method in the class.
}
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
super.tearDown()
}
Use these to clean up between testing methods back to the app's original state.
Is it possible to access and run a specific method/function from another class that can change dynamically as the app is run?
I’ll try to simplify the problem as much as possible.
SelectionPage.swift
Choose which class needs to be selected and accessed using an UIPickerView - 10 possible selections (Class1, Class2, Class3,…, Class10).
Class1.swift, Class2.swift, … Class10.swift
Each of the 10 classes has a single method that has exactly the same name but is programmed differently:
func runOnUpdate() { }
GameSceneViewController.swift
When a selection is made on the SelectionPage, the app segues to a GameSceneViewController where the specific selected function is run every time the update function is run:
override func update(currentTime: CFTimeInterval)
{
// run runOnUpdate() function here from selected class
}
Inside the update function, I would like to execute the runOnUpdate( ) function depending on which class was selected on the SelectionPage. Is this possible? Ideally I'd like to be able to assign the specific class/method in the:
override func didMoveToView(view: SKView)
so that I can access in other functions as well.
I’ve looked into lazy instantiation, creating delegates for each of the classes, #objc(Class1), arrays of [AnyClass], typealias, global variables in structs, singletons etc. but I’m unable to figure out how to make this work.
It seems like a fairly common problem so any help would be greatly appreciated! Thank you in advance!
You were correct in trying delegates as this is a case where you should make a protocol and a delegate. The protocol requires the function. From there you set the delegate property to an instance of a class that conforms to that protocol and then you call delegate?.someFunction() to call the function on the given object.
class ViewController: UIViewController {
var delegate: Updatable?
override func viewDidLoad() {
super.viewDidLoad()
let foo = Foo()
delegate = foo
delegate?.runOnUpdate() // prints do something
}
}
protocol Updatable {
func runOnUpdate()
}
class Foo: NSObject, Updatable {
func runOnUpdate() {
println("do something")
}
}