Got a strange thing that's tripping me up. Feels like there's a simple "In Swift 2 we always (or never) do this" that I'm missing, but I can't see it.
I have a Brain class, meant to be used as a singleton:
class Brain: NSObject {
static var sharedInstance : Brain?
var languageLoadedAndReadyFunction = languageLoadedAndReadyImplementation
init() {
NSNotificationCenter.defaultCenter().addObserver(self,
selector: "languageLoadedAndReady",
name: Notifications.LanguageLoadedAndReady,
object: nil)
}
func languageLoadedAndReadyImplementation() {
print("Got language Ready notification")
}
func languageLoadedAndReady() {
self.languageLoadedAndReadyFunction(self)()
}
class func get() -> Brain! {
return sharedInstance
}
//...
class func reset() {
sharedInstance = Brain()
}
deinit() {
NSNotificationCenter.defaultCenter().removeObserver(self)
}
}
In my unit test for Brain:
func testBrainRegisterForNotificationWhenWakingUp() {
let expectation = expectationWithDescription("Function should be called when the notification is received")
var brain = Brain.get()
brain.languageLoadedAndReadyFunction = {brain -> () -> () in
{
expectation.fulfill()
Brain.reset() // <-- this sets sharedInstance to a new Brain
}
}
brain.startUp() // <-- this causes the languageLoadedAndReady event to arrive at the brain
waitForExpectationsWithTimeout(5) {
error in
if let error = error {
print("Error: \(error.localizedDescription)")
}
}
}
The way I needed to define the function as "brain -> () -> ()" feels cumbersome, but it seems to work a treat. It let me see when the notification arrived, so I could verify, by test, that we're behaving correctly. The deinit() method is called after the brain is reset, indicating to me that the old brain is being removed rom memory.
Today, I'm writing some new tests for TranslatorTests.swift:
func testTranslatorCanTranslate() {
let expectation = expectationWithDescription("Function should be called when the notification is received2")
var brain = Brain.get()
brain.languageLoadedAndReadyFunction = {brain -> () -> () in
{
expectation.fulfill()
Brain.reset()
print("first TranslatorTests")
}
}
brain.startUp() // <-- 'brain' is different here than in BrainTests.swift, causes
// the closure in BrainTests.swift to be called.
waitForExpectationsWithTimeout(5) {
error in
if let error = error {
print("Error: \(error.localizedDescription)")
}
}
translator.setActiveLanguage("en")
let resultString = translator.translate("about_title")
XCTAssertEqual(resultString, "About")
}
func testTranslatorCanTranslateSecondWord() {
let expectation = expectationWithDescription("Function should be called when the notification is received3")
let brain = Brain.get()
brain.languageLoadedAndReadyFunction = {brain -> () -> () in
{
expectation.fulfill()
Brain.reset()
print("second TranslatorTests")
}
}
brain.startUp() // <-- 'brain' is different here than in BrainTests.swift, causes
// the closure in BrainTests.swift to be called.
waitForExpectationsWithTimeout(5) {
error in
if let error = error {
print("Error: \(error.localizedDescription)")
}
}
translator.setActiveLanguage("en")
let resultString = translator.translate("actmon_ready")
XCTAssertEqual(resultString, "Ready to upload")
}
When I run the tests, I get the most bizarre error: the closure in BrainTests.swift is called when the TranslatorTests.swift is executed. This causes the expectation.fulfill() method to be called a second time, causing a crash.
Incidentally, inside the closure there is no 'self' , but if I go up one level in the call stack, the 'self' refers to the previous instance of the brain. That leads me to belive that the brain -> () -> () syntax is the problem.
This boggles me. The 'brain' has a different address before each of the closures, which indicates to me that it's a different instance. In fact, the old brain has been deinited by this point, so how could it be called?
I would have thought that assigning to the variable for an instance would mean that we're giving the closure a new function to execute for this instance.
Can anyone explain this to me? Please use small words, I'm feeling a little less intelligent than I did when writing this code.
In my research, I stumbled across these two articles that helped:
http://oleb.net/blog/2014/07/swift-instance-methods-curried-functions/
https://devforums.apple.com/message/1008188#1008188
That explains to me why the call is "{brain -> () -> () in...".
The problem I had in my code was, of course, that the instance variable was declared like this in my test files:
class BrainTests: XCTestCase {
var brain: Brain!
override func setUp() {
super.setUp()
brain = Brain.get()
}
override func tearDown() {
super.tearDown()
Brain.reset()
}
func testBrainExists() {
XCTAssertNotNil(brain)
}
So, when I was calling Brain.reset() to drop the old singleton and create a new one, there was still a pointer to the original.
By removing the instance variable, the brain was reset as expected, and the callbacks then worked. I was able to set callbacks from each test case as needed to pass all my tests.
Goodness, this was a sneaky thing!
Related
Let's say I have a Swift class that stores a completion block, and does a few asynchronous tasks.
I want that block to be called by whichever of the tasks finishes first, but only that one - I don't want it to be called again when the second task finishes.
How can I implement this in a clean way?
As long as you don't need this to be thread safe, you can solve this problem with a fairly straightforward #propertyWrapper.
#propertyWrapper
struct ReadableOnce<T> {
var wrappedValue: T? {
mutating get {
defer { self._value = nil }
return self._value
}
set {
self._value = newValue
}
}
private var _value: T? = nil
}
Mark the completion block var with #ReadableOnce, and it will be destroyed after the first time it's value is read.
Something like this:
class MyClass {
#ReadableOnce private var completion: ((Error?) -> Void)?
init(completion: #escaping ((Error?) -> Void)) {
self.completion = completion
}
public func doSomething() {
// These could all be invoked from different places, like your separate tasks' asynchronous callbacks
self.completion?(error) // This triggers the callback, then the property wrapper sets it to nil.
self.completion?(error) // This does nothing
self.completion?(error) // This does nothing
}
}
I wrote up more of a detailed discussion of this here but the key thing to be aware of is that reading the value sets it to nil, even if you don't invoke the closure! This might be surprising to someone who isn't familiar with the clever property wrapper you've written.
There is already a standard expression of onceness. Unfortunately the standard Objective-C is unavailable in Swift (GCD dispatch_once), but the standard Swift technique works fine, namely a property with a lazy define-and-call initializer.
Exactly how you do this depends on the level at which you want onceness to be enforced. In this example it's at the level of the class instance:
class MyClass {
// private part
private let completion : (() -> ())
private lazy var once : Void = {
self.completion()
}()
private func doCompletionOnce() {
_ = self.once
}
// public-facing part
init(completion:#escaping () -> ()) {
self.completion = completion
}
func doCompletion() {
self.doCompletionOnce()
}
}
And here we'll test it:
let c = MyClass() {
print("howdy")
}
c.doCompletion() // howdy
c.doCompletion()
let cc = MyClass() {
print("howdy2")
}
cc.doCompletion() // howdy2
cc.doCompletion()
If you promote the private stuff to the level of the class (using a static once property), the completion can be performed only once in the lifetime of the entire program.
I don't clear about these two, Nowadays the world is shifting to the closure types. But I'm not clearly understanding this. Can someone explain me with a real-time example?
So a real life example of both would be something like this:
protocol TestDelegateClassDelegate: class {
func iAmDone()
}
class TestDelegateClass {
weak var delegate: TestDelegateClassDelegate?
func doStuff() {
DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) {
self.delegate?.iAmDone()
}
}
}
class TestClosureClass {
var completion: (() -> Void)?
func doStuff() {
DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) {
self.completion?()
}
}
}
class ViewController: UIViewController, TestDelegateClassDelegate {
func iAmDone() {
print("TestDelegateClassDelegate is done")
}
override func viewDidLoad() {
super.viewDidLoad()
let testingDelegate = TestDelegateClass()
testingDelegate.delegate = self
testingDelegate.doStuff()
let testingClosure = TestClosureClass()
testingClosure.completion = {
print("TestClosureClass is done")
}
testingClosure.doStuff()
}
}
Here we have 2 classes TestDelegateClass and TestClosureClass. Each of them have a method doStuff which waits for 3 seconds and then reports back to whoever is listening where one uses delegate procedure and the other one uses closure procedure.
Although they do nothing but wait you can easily imagine that they for instance upload an image to server and notify when they are done. So for instance you might want to have an activity indicator running while uploading is in progress and stop it when done. It would look like so:
class ViewController: UIViewController, TestDelegateClassDelegate {
#IBOutlet private var activityIndicator: UIActivityIndicatorView?
func iAmDone() {
print("TestDelegateClassDelegate is done")
activityIndicator?.stopAnimating()
}
override func viewDidLoad() {
super.viewDidLoad()
activityIndicator?.startAnimating()
let testingDelegate = TestDelegateClass()
testingDelegate.delegate = self
testingDelegate.doStuff()
activityIndicator?.startAnimating()
let testingClosure = TestClosureClass()
testingClosure.completion = {
self.activityIndicator?.stopAnimating()
print("TestClosureClass is done")
}
testingClosure.doStuff()
}
}
Naturally you would only use one of the two procedures.
You can see there is a huge difference in code. To do a delegate procedure you need to create a protocol, in this case TestDelegateClassDelegate. A protocol is what defines the interface of a listener. And since an iAmDone method is defined it must be defined in ViewController as well as long as it is defined as TestDelegateClassDelegate. Otherwise it will not compile. So anything declared as TestDelegateClassDelegate will have that method and any class can call it. In our case we have weak var delegate: TestDelegateClassDelegate?. That is why we can call delegate?.iAmDone() without caring what delegate actually is. For instance we can create another class:
class SomeClass: TestDelegateClassDelegate {
func iAmDone() {
print("Something cool happened")
}
init() {
let testingDelegate = TestDelegateClass()
testingDelegate.delegate = self
testingDelegate.doStuff()
}
}
So a good example for instance is an UITableView that uses a delegate and dataSource (both are delegates, just properties are named differently). And table view will call the methods of whatever class you set to those properties without needing to know what that class is as long as it corresponds to the given protocols.
Same could be achieved with closures. A table view could have been defined using properties giving closures like:
tableView.onNumberOfRows { section in
return 4
}
But that would most likely lead into one big mess of a code. Also closures would in this case be giving many programmers headaches due to potential memory leaks. It is not that closures are less safe or anything, they just do a lot of code you can't see which may produce retain cycles. In this specific case a most likely leak would be:
tableView.onNumberOfRows { section in
return self.dataModel.count
}
and a fix to it is simply doing
tableView.onNumberOfRows { [weak self] section in
return self?.dataModel.count ?? 0
}
which now looks overcomplicated.
I will not go into depths of closures but in the end when you have repeated call to callbacks (like in case of table view) you will need a weak link either at delegate or in closure. But when the closure is called only once (like uploading an image) there is no need for a weak link in closures (in most but not all cases).
In retrospective use closures as much as possible but avoid or use caution as soon as a closure is used as a property (which is ironically the example I gave). But you would rather do just this:
func doSomethingWithClosure(_ completion: #escaping (() -> Void)) {
DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) {
completion()
}
}
And use it as
doSomethingWithClosure {
self.activityIndicator?.stopAnimating()
print("TestClosureClass is done")
}
This has now removed all potential risks. I hope this clears a thing or two for you.
In Swift/obj-c the term delegate is used to refer to a protocol that responds to specific selectors.
Thing about it just like calling a method on an object.
E.g.
protocol CalculatorDelegate : class { // : class so it can be made 'weak'
func onCalculation(result: Int) -> Void
}
Now if we have a Calculator class, to use the delegate we'd do something like
class Calculator() {
weak var delegate: CalculatorDelegate?
func calculate(_ a: Int, _ b: Int) -> Int {
let result = a + b
self.delegate?.onCalculation(result: result)
return result
}
}
Then in some other class (e.g. in iOS - a View Controller) we might do:
class MyClass : CalculatorDelegate {
func onCalculation(result: Int) {
print("Delegate method on calculation called with result \(result)")
}
func someButtonPress() {
let calculator = Calculator()
calculator.delegate = self
calculator.calculate(42, 66)
}
}
So you can see how the setup is quite elaborate.
Now closures are simply blocks of code that can be called in other places, so you could change all of the code like so:
class Calculator2() {
weak var delegate: CalculatorDelegate?
func calculate(_ a: Int, _ b: Int, onCalculation: (#escaping (Int) -> Void) -> Int)?) {
let result = a + b
onCalculation?(result)
return result
}
}
class MyClass {
func someButtonPress() {
let calculator = Calculator2()
calculator.calculate(42, 66, onCalculation: { (result: Int) in
print("Closure invoked with \(result)")
})
}
}
However, with closures you need to be aware that it is a lot easier to shoot yourself in the foot by capturing variables (e.g. self) strongly, which will lead to memory leaks even under ARC regime.
Closures are first-class objects so that they can be nested and passed around
Simply,
In swift, functions are primitive data types like int, double or character that is why you can pass a function in the function parameter. In swift mechanism simplify in closures syntax like lambda expression in other languages.
E.g. If you want to call rest API through URSSession or Alamofire and return response data then you should use completionHandler(it's closure).
Void closure : - {(paramter:DataType)->Void}
Return closure : - {(paramter:DataType)->DataType}
e.g. (int, int) -> (int)
https://docs.swift.org/swift-book/LanguageGuide/Closures.html
I have a class attribute that points to one of the class functions. However when I try to initialize this variable with one of the functions, I get the following error:
'self' used in method call before all stored properties are initialized.
I'm able to initialize any other variable to those functions, but the error makes it sound like I'm calling the function even though I'm not.
import UIKit
import AudioToolbox
class BeatMaker {
// iPhone 7 and up use beat function, iPhone 6s use beatFallback
let hapticFunction: () -> ()
let impactGenerator = UIImpactFeedbackGenerator.init(style: .heavy)
init(supportsImpactGenerator: Bool) {
// error 1: 'self' used in method call 'beat' before all stored properties are initialized
// error 2: 'self' used in method call 'beatFallback' before all stored properties are initialized
self.hapticFunction = (supportsImpactGenerator) ? beat : beatFallback
}
private func beat() {
impactGenerator.impactOccurred()
}
private func beatFallback() {
AudioServicesPlaySystemSound(1520)
}
func makeABeat() {
hapticFunction()
}
}
In this specific case I want to make use of the Taptic Engine and simulate a click through the UIImpactFeedbackGenerator. The iPhone 6s doesn't support this engine, so I want to call a fallback function that produces a similar effect.
I also tried initializing the variable on the spot:
// this works
var hapticFunction: (BeatMaker) -> () -> () = beat
init(supportsImpactGenerator: Bool) {
if !supportsImpactGenerator {
// error: Cannot assign value of type '() -> ()' to type '(BeatMaker) -> () -> ()'
self.hapticFunction = beatFallback
// produces same error
self.hapticFunction = beatFallback.self
}
}
I know that I could make everything static or put everything out of the class, but this feels like it should work yet it doesn't. Am I missing something?
EDIT
Setting the type of type of hapticFunction to an optional seems to work, but this doesn't make any sense to me. What's the difference?
// this works
var hapticFunction: (() -> ())?
init(supportsImpactGenerator: Bool) {
self.hapticFunction = (supportsImpactGenerator) ? beat : beatFallback
}
It might be better to not use a Bool, but rather a nested Enum, which is also more extendible if you wanna add some other modes of haptic feedback later on.
I have a generalized solution for a generalized problem of your question. So either you do:
public class FunctionOwner {
private let mode: Mode
public init(`do` mode: Mode = .default) {
self.mode = mode
}
}
public extension FunctionOwner {
enum Mode {
case foo, bar
}
func fooOrBar() {
switch mode {
case .foo: foo()
case .bar: bar()
}
}
}
private extension FunctionOwner {
func foo() {
print("doing foo")
}
func bar() {
print("doing bar")
}
}
public extension FunctionOwner.Mode {
static var `default`: FunctionOwner.Mode {
return .foo
}
}
// USAGE
FunctionOwner(do: .bar).fooOrBar() // prints "doing foo"
FunctionOwner(do: .foo).fooOrBar() // prints "doing bar"
Or if you for some reason do want to keep the stored Mode, you can do this (might be relevant for your actual question on how you do a workaround of referencing self in the init.):
public class FunctionOwner {
private let _function: (FunctionOwner) -> Void
public init(`do` mode: Mode = .default) {
_function = { functionOwner in
switch mode {
case .foo: functionOwner.foo()
case .bar: functionOwner.bar()
}
}
}
}
public extension FunctionOwner {
enum Mode {
case foo, bar
}
func fooOrBar() {
_function(self)
}
}
// The rest of the code is the same as the example above
There are two method to fix this
You can:
Give hapticFunction a initial value like {}
or fix like:
class BeatMaker {
let impactGenerator = UIImpactFeedbackGenerator.init(style: .heavy)
let supportsImpactGenerator: Bool
init(supportsImpactGenerator: Bool) {
self.supportsImpactGenerator = supportsImpactGenerator
}
private func beat() {
if supportsImpactGenerator {
impactGenerator.impactOccurred()
} else {
AudioServicesPlaySystemSound(1520)
}
}
func makeABeat() {
beat()
}
}
My closure retains itself. It causes capturing all other objects inside. I can pass such objects using weak reference, but it doesn't solve the problem of retain cycle. What's the right way to do recursion with closures without retain cycles?
class Foo {
var s = "Bar"
deinit {
print("deinit") // Won't be executed!
}
}
class TestVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let foo = Foo() // Weak works, but not the right solution.
var closure: () -> Void = { return }
closure = {
print(foo.s)
if true {
return
} else {
closure()
}
}
}
}
You have an unusual setup where your closure retains itself. Note that Swift doesn't allow you to create a weak reference to a closure.
To break the retain cycle, set closure to { } in the base case of the recursion. Here's a test macOS command-line program:
func test() {
var closure: ((Int) -> ()) = { _ in }
closure = { i in
if i < 10 {
closure(i + 1)
} else {
// Comment out this line for unbounded memory consumption.
closure = { _ in }
}
}
closure(0)
}
while true {
test()
}
If you run this, its memory consumption is flat.
If you comment out the line in the base case that resets closure, its memory consumption grows without bound.
Your closure is holding foo instance reference.
foo will be released as soon as the closure is released.
closure is calling itself. If we pass weak self inside closure then that should be fine. OR by resetting closure
below code should work fine.
var closure: () -> Void = { return }
override func viewDidLoad() {
super.viewDidLoad()
let foo = Foo()
closure = { [weak self] in
print(foo.s)
if true {
return
} else {
self?.closure()
}
}
}
OR initialize foo inside closure
override func viewDidLoad() {
super.viewDidLoad()
var closure: () -> Void = { return }
closure = { [weak self] in
let foo = Foo()
print(foo.s)
if true {
return
} else {
self?.closure()
}
}
}
Turn your closure into a nested function:
class Foo {
var s = "Bar"
deinit {
print("deinit")
}
}
class TestVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let foo = Foo()
func nestedFunction() {
print(foo.s)
if true {
return
} else {
nestedFunction()
}
}
nestedFunction()
}
}
In Swift nested functions can refer to themselves synchronously (recursive functions) or asynchronously (typically for asynchronous iteration), can do so without any reference cycle, and can capture variables just as well as closures do. You can even have mutually recursive nested functions.
You could instead reset the closure-containing variable to a dummy closure once done, I am not saying this does not work, but this is very error-prone, especially when the closure calls itself asynchronously: the reset has to be done asynchronously as well in that case. Better have the lack of a reference cycle be ensured statically, as can be done most everywhere else in Swift.
(The concept used to have a bad rap due to an implementation in the C language by gcc that introduced security holes as a result of attempting to squeeze a closure reference into a C function pointer i.e. a code address, but Swift nested functions have nothing to do with that)
It doesn't seem like I can cast a generic type to another? Swift is throwing DynamicCastClassException.
Basically here is the problem:
// T is defined as T: NSObject
let oebj1 = NetworkResponse<User>()
let oebj2 = oebj1 as NetworkResponse<NSObject>
Here is why I need to do this casting
class BaseViewController: UIViewController {
// Not allowed to make a generic viewController and therefore have to cast the generic down to NSObject
func fetchData(completion: (NetworkResponse<NSObject>)->()) {
fatalError("You have to implement fetchData method")
}
}
class UsersViewController: BaseViewController {
override func fetchData(completion: (NetworkResponse<NSObject>)->()) {
userNetworkManager.fetchUsers { networkUSerResponse in
completion(networkUSerResponse as NetworkResponse<NSObject>)
}
}
}
class UserNetworkManager {
func fetchUsers(completion: (NetworkResponse<User>)->()) {
// Do stuff
}
}
In general, there doesn't seem to be a way to do this. The basic problem is that NetworkResponse<NSObject> and NetworkResponse<User> are essentially completely unrelated types that happen to have identical functionality and similar naming.
In this specific case, it really isn't necessary since you're throwing away the known Userness of the result anyway, meaning that if you really want to treat it as a User later you'll have to do a conditional cast back. Just remove the generic from NetworkResponse and it will all work as expected. The major drawback is that within UserVC.fetchData you won't have access to the returned User result without a (conditional) cast.
The alternative solution would be to separate out whatever additional information is in NetworkResponse from the payload type (User/NSObject) using a wrapper of some sort (assuming there's significant sideband data there). That way you could pass the NetworkResponse to super without mutilation and down-cast the payload object as needed.
Something like this:
class User : NSObject {
}
class Transaction {
let request:NSURLRequest?
let response:NSURLResponse?
let data:NSData?
}
class Response<T:NSObject> {
let transaction:Transaction
let payload:T
init(transaction:Transaction, payload:T) {
self.transaction = transaction
self.payload = payload
}
}
class UserNetworkManager {
func fetchUsers(completion: (Response<User>) -> ()) {
completion(Response(transaction:Transaction(), payload:User()))
}
}
let userNetworkManager = UserNetworkManager();
class BaseVC {
func fetchData(completion: (Response<NSObject>) -> ()) {
fatalError("Gotta implement fetchData")
}
}
class UserVC : BaseVC {
override func fetchData(completion: (Response<NSObject>) -> ()) {
userNetworkManager.fetchUsers { response -> () in
completion(Response(transaction: response.transaction, payload: response.payload))
}
}
}
Although at that point, you're probably better off just separating the transaction information and payload information into separate arguments to the callback.