All posts by admin

callbacks in swift

https://medium.cobeisfresh.com/why-you-shouldn-t-use-delegates-in-swift-7ef808a7f16b

CallBackSwift demo

Using callbacks for delegation

Callbacks are similar in function to the delegate pattern. They do the same thing: letting other objects know when something happened, and passing data around.

What differentiates them from the delegate pattern, is that instead of passing a reference to yourself, you are passing a function. Functions are first class citizens in Swift, so there’s no reason why you wouldn’t have a property that is a function!

MyClass now has a myFunction property that it can call and anyone can set (since properties are internal by default in Swift). This is the basic idea of using callbacks instead of delegation. Here’s the same example as before but with callbacks instead of a delegate:

1) we declare a class called NetworkService

2) We create a function type, called onComplete, that takes in a parameter of String type and returns Void. We make it into an optional so that we can take advantage of Optional Chaining, where we can query the reference. If its valid, great. If its nil, it would return nil and will not crash.

3) We create a function called fetchDataFromUrl that simulates getting data from a server by using sleep. After 2 seconds, granted something came back, we call our callback function property. However! Note here that our onComplete is defaulted to nil. Hence if we call onComplete in fetchDataFromUrl, it will query the nil and get nil back. Nothing will happen. In order for something to happen, we need to implement the onComplete optional function. You can implement onComplete in NetworkService initializer or externally since our onComplete is public.

a) Hence, usually, we will instantiate an object of our class. We have a reference to that object called service.
b) We then declare the callback definition for onComplete.
c) Finally, we call fetchDataFromUrl. After it runs through the function implementation, it calls the onComplete function as defined in b)

Another way to use callbacks – Data has changed!

1) as always, declare your callback. This time, we’re declaring the function type as having a parameter of “an array of String”, and returns void. Let’s call this property onUsernamesChanged

2) implement an init for our class, and define the definition for our callback. Since our callback’s function type has a parameter of an array of String, we use names as an identifier for that parameter.

3) Then, we simply use it in didSet.

Thus, another great way to use callbacks is when you want to get notified data has been changed.

Full Source Code

So why are callbacks better?

Decoupling

Delegates lead to pretty decoupled code. It doesn’t matter to the NetworkService who its delegate is, as long as they implement the protocol.

However, the delegate has to implement the protocol, and if you’re using Swift instead of @objc protocols, the delegate has to implement every method in the protocol. (since there’s no optional protocol conformance)

When using callbacks, on the other hand, the NetworkService doesn’t even need to have a delegate object to call methods on, nor does it know anything about who’s implementing those methods. All it cares about is when to call those methods. Also, not all of the methods need to be implemented.

Multiple delegation

What if you want to notify a ViewController when a request finishes, but maybe also a some sort of logger class, and some sort of analytics class.
With delegates, you would have to have an array of delegates, or three different delegate properties that might even have different protocols! (I’ll be the first to admit I’ve done this)

With callbacks, however, you could define an array of functions (I love Swift) and call each of those when something’s done. There’s no need to have a bunch of different objects and protocols risking retain cycles and writing boilerplate code.

Clearer separation of concerns

The way I see the difference between delegates and callbacks is that with delegates, the NetworkService is telling the delegate “Hey, I’ve changed.” With callbacks, the delegate is observing the NetworkService.
In reality, the difference is minimal, but thinking in the latter way helps prevent anti-patterns often found with delegation, like making the NetworkService transform results for presentation, which should not be its job!

Easier testing!
Ever felt like your codebase is twice as big with unit tests, because you have to mock every protocol, including all of the delegates in your app?
With callbacks, not only do you not have to mock any delegates, but it lets use use whatever callback you want in each test!
In one test, you might test if the callback gets called, then in another you might test if it’s called with the right results. And none of those require a complicated mocked delegate with someFuncDidGetCalled booleans and similar properties.

Optional Types

http://lithium3141.com/blog/2014/06/19/learning-swift-optional-types/

“But wait,” you say, “Int is a value type, not an object! How can I use nil for a value?…”

Well, you’re right. NSInteger didn’t have a nil value (or, rather, using nil with the right coercion would get you an integer with a value of 0).

Instead, we defined a ton of marker values that meant “no value:”: 0, 1, NSIntegerMin, NSIntegerMax, and NSNotFound all mean “nothing” in some API.

When you stop to think about it, this is really a limitation: by not having a consistent, defined way of saying no integer value, we’re layering a tiny bit of additional complexity around any use of such a value, then attempting to paper over it with documentation. Want to find an object in an array? Well, if that object doesn’t exist, you get NSNotFound – but if you try to find a nonexistent row in a table view, you get -1 instead.

Swift defines a new type called Optional that always has exactly one of two values: a defined “nothing” value called None, or a wrapped-up value of some other type T.

It’s as if Swift can take regular values and place them inside a box, which may or may not be empty:

In this example, the first integer is a plain Int type.

The second and third, though, are both of type Optional – or, for short, Int?.

Notice that the third value here is actually an “empty box” (the None value), even though its type is Int?.

This ability, to pass around None anywhere an optional type can go, is how Swift can provide things like nil for value types like Int (or, for that matter, any type, whether value or reference). Since this value will have the same type as a “real” value wrapped up in Optional, they can both be represented in the same variable without trying to rely on special values to stand in for the concept of “no value.”

Given:

We need some way of getting at the value inside an optional’s box – and, for that matter, checking whether such a value exists at all! Thankfully, Swift has us covered with the ! operator, which extracts the value out of an optional:

This works great for optionals that have a value. But what about those that don’t?

The ! operator only applies to optionals that have an actual value inside them. If your optional has nil (an alias for .None), it can’t be unwrapped and will throw a runtime error.

Let’s make our code a bit smarter. Instead of unconditionally unwrapping our optional value, we can check whether the value is nil first – much like we might have done in Objective-C.

Not very good way of checking whether the value is nil

Swift has us covered here too, with a syntax called optional binding. By combining an if and a let statement, we can write a concise one-line check for a newly-bound variable that is only conjured into existence if there’s a real value to go along with it:

Chaining – calling methods on those variables

Your program might have some custom classes – most do, after all – and you could want to call a method on an variable that might be an instance, or might be nil.
Developers can make use of optional chaining to call methods on potentially-nil objects:

By sticking a ? between the variable name and method call, we can indicate that we want either a real answer back (in the event that y is a valid instance) or another nil (in the case that y is itself nil).

Even though someMethod() is declared to return an Int, z gets type Optional because we used optional chaining to call the method.

This might seem like a hassle, but can actually be helpful, especially when combined with optional binding from above. If we stick with the same class definition, we can try something like this:

This remains concise while still dealing with all the various concerns we might have:

If y is nil (as it is here), the optional chaining will still allow us to write this code without a type error.

If y is nil or someMethod() returns nil, the optional binding will catch that case and avoid giving us a nil value for non-optional z.

In the event we do get a z, we’re not required to hand-unwrap it because it’s optionally bound.

All in all, this is a pretty clean system for passing around nil values for just about any type. We get some extra type safety out of the deal, avoid using specially defined values, and can still be just as concise as Objective-C – if not more!

Rough Edges

Unary ? operator – Not valid for Swift 3.

It’s valid Swift to take an optional variable and throw a ? at the end (Not for > Swift 3). However, unlike the unwrapping operator !, appending ? doesn’t actually affect the variable in any way: it is still optional.

Surrounding if checks will still look to see if the variable is nil, rather than evaluating its contained truth value (if any).

This can cause extra trouble when combined with Optional Bool

Since the Optional type is defined using generics (it can wrap any other type in the language) it’s possible to construct an optional boolean variable. In fact, it’s virtually mandatory the language allow this: to special-case Bool to disallow optionals would be an exceptional change, requiring serious modifications to the language or the Optional type.

That does, however, lead to a way developers can construct a kind of three-state variable: an Optional can be true, false, or nil. (What the latter means is rather context-dependent.) This can be very misleading, though, when combined with an if check:

Any vs AnyObject

https://medium.com/@mimicatcodes/any-vs-anyobject-in-swift-3-b1a8d3a02e00

AnyObject can represent an instance of any class type

Any can represent an instance of any type at all, including function types and optional types.

Tuples

Tuples in Swift occupy the space between dictionaries and structures: they hold very specific types of data (like a struct) but can be created on the fly (like dictionaries). They are commonly used to return multiple values from a function call.

You can create a basic tuple like this:

Named Types vs Compound Types

Swift Functions as Types

Named Types are those which are defined and identified by the name that they’re given. Classes, structs, enums, and protocols fit this category of Type.

Initializing instances of Types and using their properties and methods, passing them around to functions that require parameters of those Types, or setting them as values to properties of other Types are all pretty standard thoughts that come to mind when using named Types.

Compound Types (Functions, Tuples)

Compound Types, on the other hand, don’t have names. Rather, they have “signatures” that define and identify them as Types. Swift has two compound Types: functions and tuples.

Now I know what you might be thinking: “Functions have names!”

Indeed many do. But when we’re thinking about them in terms of their Type-ness. We’ve got to go beyond the name to the function’s “signature” characteristics.

The name of a function (or tuple, since they can be type-aliased) is simply how we refer to the function in code to execute it or pass it around as an argument.

The “signature” of the function, however, is the part that characterizes the function as a Type.

Function Types

What exactly makes up a function’s Type-ness or “signature” as I’ve been calling it? Two things:

The Type(s) of its parameters
The Type that the function returns

Given:

“What is the generateStarWarsName function’s Type?”,

answer: “generateStarWarsName is a function Type that has three parameters, the first two of Type String, the last of Type Int, and that returns a value of Type String.”

Given the above generateStarWarsName function, we could notate its Type as follows:
(String, String, Int) -> String

Remove “generateStarWarsName”, “firstName: “, “lastName: “, and “birthYear: ” and you’re left with that raw Type information. What remains is the function’s Type notation.

It tells you (and the Swift compiler) everything you need to know to be able identify the Type of that function… it’s “signature”, if you will.

examples:

func returnHelloString() -> String {}, () -> String
func sayHello() {}, () -> Void
func complimentMe(name: String) -> String {}, (String) -> String
func countToTen() {}, () -> Void
func addInts(first: Int, second: Int) -> Int {}, (Int, Int) -> Int
func fadeIn(duration: NSTimeInterval, delay: NSTimeInterval, completion: (Bool) -> Void){}, (NSTimeInterval, NSTimeInterval, (Bool)->Void) -> Void

Coalescing Operator

https://www.hackingwithswift.com/example-code/language/what-is-the-nil-coalescing-operator

Because name is an optional string, we need to unwrap it safely to ensure it has a meaningful value.

There are many ways to wrap it, for example, Optional Binding:

or guard:

nil coalescing operator

Swift’s nil coalescing operator helps you solve this problem by either unwrapping an optional if it has a value, or providing a default if the optional is empty.

The nil coalescing operator – ?? – does exactly that, but if it finds the optional has no value then it uses a default instead. In this case, the default is “Anonymous”. What this means is that unwrappedName has the data type String rather than String? because it can be guaranteed to have a value.

You don’t need to create a separate variable to use nil coalescing. For example, this works fine too:

SetNeedsLayout vs LayoutIfNeeded

setNeedsLayout vs layoutIfNeeded Explained


https://developer.apple.com/library/content/documentation/General/Conceptual/Devpedia-CocoaApp/MainEventLoop.html
https://medium.com/@abhimuralidharan/ios-swift-setneedslayout-vs-layoutifneeded-vs-layoutsubviews-5a2b486da31c

Explanation 1: When an iOS app launches, UIApplication in iOS starts the main run loop for an app, which runs on the main thread. The main run loop processes events (such as user touches) and handles updates to view-based interfaces. As events occur, such as touch, location updates, motion, and multimedia control, the run loop finds the appropriate handler for the events, calling appropriate methods, which call other methods, and so on. At some moment in time, all events will have been handled and control will return to the run loop. Let’s label this point where control is returned to the run loop as the update cycle.

Thus, in the main event loop, an application continuously routes incoming events to objects for handling and, as a result of that handling, updates its appearance and state. An event loop is simply a run loop: an event-processing loop for scheduling work and coordinating the receipt of events from various input sources attached to the run loop.

While events are being processed and dispatched, and as changes to views are requested, they are not always acted upon right away. Instead, the system records the changes and marks views as needing to be redrawn. When are the changes drawn? It is in this update cycle, after all existing events have been handled, that attention is now turned to redrawing. Of course to the user it does not look like there is a wait to redraw (in general), because all of this is happening quickly. Knowing that there is an interval periodically, between sets of events being processed, where the system now takes on the task of updating the layout and display, is important for understanding setNeedsLayout and layoutIfNeeded.

setNeedsLayout
The method setNeedsLayout for a UIView tells the system that you want it to layout and redraw that view and all of its subviews, when it is time for the update cycle. This is an asynchronous activity, because the method completes and returns immediately, but it isn’t until some later time that the layout and redraw actually happens, and you don’t know when that update cycle will be.

layoutIfNeeded

In contrast, the method layoutIfNeeded is a synchronous call that tells the system you want a layout and redraw of a view and its subviews, and you want it done immediately without waiting for the update cycle. When the call to this method is complete, the layout has already been adjusted and drawn based on all changes that had been noted prior to the method call.

The method layoutIfNeeded is a synchronous call that tells the system you want a layout and redraw of a view and its subviews, and you want it done immediately without waiting for the update cycle.

Pointing delegate to where the delegate implementation is

Most of the time, the delegate implementation is at the current source file where the delegate and its owning object is created.

But sometimes its not.

For example, say we have a UIView called caliGuestView. We want to set up a popover control in that class.

There is a custom made popover control like so:

Due to subclassed UIView, we know to drag a UIView component into the xib, then put Popover in its custom class tab. Thus we now have the custom made control in our xib. Once that’s done, we ctrl drag it into our source file and its ready to go.

CaliGuestView.swift

CaliGuestView.swift

Initially we think, ok, we get the delegate to point here in the CaliGuestView class. Then we implement the delegate methods in this class.
BUT! what if we have delegate functionality implemented elsewhere (like MyCustomCell.m). How do we get the delegate to point where the implementation is?

1) DO NOT ASSIGN the delegate here (in CailGuestView). Simply initialize it as is.

CaliGuestView.swift

2) make sure MyCustomCell’s delegate implementation is set

MyCustomCell.m

3) let MyCustomCell’s instance of this class point to self

MyCustomCell owns the CaliGuestView, and thus can simply access its delegate. Then point that delegate to self.

MyCustomCell.m