Sometimes traversing through the life-cycle callbacks of view loading on the iPhone still gives me a headache. Especially when using Interface Builder (IB) as part of the UI development, finding the right method to override in order to get your custom drawing/init/etc. done can be more difficult than it may seem. Recently, I was lost again in the quagmire of methods to choose from when building a custom UIView subclass that provided some basic look-and-feel customization over the standard view structure The answer that was revealed to me is today’s tip.
awakeFromNib
The commonly recommended place to do custom initialization for custom views is in the initWithFrameor initWithCoder methods. When you are defining parts of your UI in IB, initWithCoder is the one of these that is called by the nib-loading code. However, it is usually the case that any work done with members declared as IBOutlet are still nil at this point, so your custom changes will fall on deaf ears. This drives many developers to put custom initialization code in the viewDidLoad method of the view controller…because it works. The problem here is a conceptual one. You are no longer encapsulating all of the custom functionality for your view in the view class, some of the required custom code is leaking out into the controller. You are now relying on code in the custom view’s container to provide some of the needed functionality to properly initialize the view, which makes the code brittle.
Enter awakeFromNib; a UIKit addition to NSObject that receives a message from the nib-loading code after all the outlets and actions have been connected for all objects inside the nib file. Apple states that “When an object receives an awakeFromNib message, it is guaranteed to have all its outlet and action connections already established.” This means you can now comfortably make some changes to properties that would have otherwise been nil during the init phase. This allows you to put that custom code back into the view subclass, properly encapsulating the functionality.
as? Types – means the down casting process is optional. The process can be successful or not(system will return nil if down casting fails).Any way will not crash if down casting fails.
as! Type? – Here the process of down casting should be successful (! indicates that) . The ending question mark indicates whether final result can be nil or not.
More info regarding “!” and “?”
Let us take 2 cases
Consider:
let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as? UITableViewCell
Here we don’t know whether the result of down casting of cell with identifier “Cell” to UITableViewCell is success or not. If unsuccessful then it returns nil( so we avoid crash here). Here we can do as given below.
if let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as? UITableViewCell {
// If we reached here it means the down casting was successful
}
else {
// unsuccessful down casting
}
So let us remember it like this – If ? it means we are not sure whether value is nil or not (question mark comes when we don’t know things).
Contrast that to:
let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! UITableViewCell.
Here we tell the compiler that down casting should be successful. If it fails the system will crash. So we give ! when we are sure that value is non nil.
When I encountered these two type aliases while parsing JSON data for the first time, I had no idea how to distinguish or implement them properly. So, what are they? Any and AnyObject are two special types in Swift that are used for working with non-specific types.
According to Apple’s Swift documentation,
Any can represent an instance of any type at all, including function types and optional types.
AnyObject can represent an instance of any class type.
Okay, simple enough — Any is used for all types, AnyObject is used for Class types, right?
To understand how they really behave in code, I decided to play with them in a Playground.
Any allowed me to work with a mix of different types including function and non-class types such as Int, String, and Bool. According to the documentation, the elements in this array are Structs that are value types, so in theory AnyObject shouldn’t work in these cases.
To verify this I attempted to include Strings and Ints, which are value types in Swift, using AnyObject.
As expected, the compiler threw me an error saying that the elements did not conform to the type AnyObject in the array. Gotcha!
Then, this strange thing happened when I tried to follow the compiler’s suggestions:
What just happened?! How was I able to use AnyObject on Ints and Strings by explicitly casting each element to AnyObject?
I then printed the anyObjectArray into console.
The element Hi obviously looked like a string to me, but it did not have quotes around like a normal String value in Swift!
Next I printed each element using a for-in loop to check its actual type rather than its casted-type of AnyObject.
First, I used is operator to see whether the elements are Swift Struct types or not.
It is of type String! Then how could it be casted to AnyObject? Again, Strings in Swift are Structs, not Class types. Thus in theory, I shouldn’t be able to cast them as AnyObject.
I was utterly confused, and decided to do some more experiments with it. This time I used NSNumber and NSString, which are Objective-C types, to check the type of each element.
Wait, Hi is also a NSString and numeric elements are NSNumber! And… they are reference types in Objective-C! Was this the reason why Hi didn’t have quotes on it in console? I wrote some more code as below to see if my assumption was correct. 🔎
Confirmed! The elements that are casted to AnyObject in the array are now class types of Objective-C: NSString and NSNumber.
As part of its interoperability with Objective-C, Swift offers convenient and efficient ways of working with Cocoa frameworks. Swift automatically converts some Objective-C types to Swift types, and some Swift types to Objective-C types. Types that can be converted between Objective-C and Swift are referred to as bridged types.
Anywhere you can use a bridged Objective-C reference type, you can use the Swift value type instead. This lets you take advantage of the functionality available on the reference type’s implementation in a way that is natural in Swift code. For this reason, you should almost never need to use a bridged reference type directly in your own code. In fact, when Swift code imports Objective-C APIs, the importer replaces Objective-C reference types with their corresponding value types. Likewise, when Objective-C code imports Swift APIs, the importer also replaces Swift value types with their corresponding Objective-C reference types.”
In other words, the compiler does its best to be flexible in handling such types through automatic conversion and bridging while preventing our app from crashing easily. Brilliant!
Sowhen do we actually use AnyObject? As stated in Apple’s documentation, AnyObject can be used for working with objects that derive from Class but that don’t share a common root Class.
But is it absolutely necessary to use it in our code?
My answer to this question is: No.
Apple says:
In Swift 3, the id type in Objective-C now maps to the Any type in Swift, which describes a value of any type, whether a class, enum, struct, or any other Swift type. This change makes Objective-C APIs more flexible in Swift, because Swift-defined value types can be passed to Objective-C APIs and extracted as Swift types, eliminating the need for manual “box” types.
These benefits also extend to collections: Objective-C collection types NSArray, NSDictionary, and NSSet, which previously only accepted elements of AnyObject, now can hold elements of Any type. For hashed containers, such as Dictionary and Set, there’s a new type AnyHashable that can hold a value of any type conforming to the Swift Hashable protocol.
It seems that Any alone works perfectly fine in bridging these two languages in Swift 3 without the need for the use of AnyObject!
So what was the ultimate reasoning behind these changes?
In their own words, Apple explains:
Swift 3 interfaces with Objective-C APIs in a more powerful way than previous versions. For instance, Swift 2 mapped the id type in Objective-C to the AnyObject type in Swift, which normally can hold only values of class types. Swift 2 also provided implicit conversions to AnyObject for some bridged value types, such as String, Array, Dictionary, Set, and some numbers, as a convenience so that the native Swift types could be used easily with Cocoa APIs that expected NSString, NSArray, or the other container classes from Foundation. These conversions were inconsistent with the rest of the language, making it difficult to understand what exactly could be used as an AnyObject, resulting in bugs.
One would insist, however, that we iOS developers always need to be as specific as possible in terms of using types in code.
Think about this scenario: We are working with number 12.5 in Swift. In this case we would specifically state that it is a type of Double or Float rather than declare it of type Any. This way, we can conveniently access different properties or methods that are available for that specific type. In this context, we would use AnyObject for Class types because they are a little more specific than Any. But again, the use of AnyObject is just an option.
I hope this blog post helped many of you awesome developers out there on clarifying Any and AnyObject. Use Any confidently in Swift 3 while working with Objective-C backed APIs.
An enumeration is a data type consisting of a set of named values, called members. Apple doc says:
An enumeration defines a common type for a group of related values and enables you to work with those values in a type-safe way within your code.
Enumerations in Swift are much more flexible, and do not have to provide a value for each case of the enumeration. If a value (known as a “raw” value) isprovided for each enumeration case, the value can be a string, a character, or a value of any integer or floating-point type.
Enumeration Syntax
You introduce enumerations with the enum keyword and place their entire definition within a pair of braces:
enum SomeEnumeration {
// enumeration definition goes here
}
example with type:
enum Gender :String{ case Male case Female }
example without type:
enum Gender { case Male case Female }
The values defined in an enumeration (such as Male and Female) are its enumeration cases. You use the case keyword to introduce new enumeration cases.
Alternatively, you can declare it like :
enum Gender :String { case Male, Female // in a single line like this, separated by commas }
Each enumeration definition defines a brand new type. So, obviously it should have a name starting with capital letter.
We can now set a variable to a enumeration case like so:
var gender: Gender = Gender.male or in short as
var gender = Gender.male
Switch Statement using enums :
switch gender { case .male: print(“Gender is male”) case .female: print(“Gender is female”) // default case is not needed }
Note: In the above example, we don’t use the default case as all the possible enum members are taken care. Only what’s in our enums needs to be checked for. If you do not exhaust all the enum members, then you should add the default case.
HashValue vs RawValue
If you had the enum as we had declared earlier without the type, there is no rawValue available but instead you get a member called hashValue. All enums get a hashValue which is basically like an Index to the order in which the enums were declared. So in the enum called Gender declared above, malewill have a hashValue of 0 and female will have a hashvalue of 1. The reason for this is that hashValues are based on the first item having the index value of 0.
The rawValue on the other hand is a type value that you can assign to the enum members.
enum Gender :String { // enum with type
case male = “I am male”
case female
}
print(Gender.male) // prints “male”
print(Gender.male.rawValue) // prints “I am male”
print(Gender.male.hashValue) // prints 0
accessing values with enums without type:
enum Gender { // enum without type
case male
case female
}
print(Gender.male) // prints “male”
print(Gender.male.rawValue) // Error. rawvalue cannot be accessed for enums without type
print(Gender.male.hashValue) // prints 0
User defined values :
Enum case cannot have a raw value if the enum does not have a raw type.
If enum type is defined, then it cannot have other datatypes as enum member cases.
enum Gender {
case male = 1 //error: enum case cannot have a raw value if the enum does not have a raw type
case female
}
You could use the enum with defined values if enum is having a raw type:
enum Genres:Int{ case One = 1001, Two, Three, Four, Five }
This now enumerates the values and assigns genre.One with 1001 and genres.Two with 1002 and so on.
Note that with this declaration we have also added the var type after the name of the enum. To get the value stored in that enum member, you need to access it’s rawValue property as println("Result -> (genres.Two.rawValue)") // prints "1002"
When integers are used for raw values, they auto-increment from previous value if no value is specified.
Now, consider the above enum of genres. If one equals 1001, two is given a value of 2000, and if three is not given any value, then the raw value of three will give you 2001.
Enum Genres:Int{ case One = 1001, Two = 2000, Three, Four, Five } print(Genres.Three) // prints "2001"
Enums with methods:
Enums can have methods which can be used on enum cases:
enum Student { case Name(String) case Mark(Int,Int,Int) } var studDetails = Student.Name("Swift") var studMarks = Student.Mark(98,97,95) switch studMarks { case .Name(let studName): println("Student name is: (studName).") case .Mark(let Mark1, let Mark2, let Mark3): println("Student Marks are: (Mark1),(Mark2),(Mark3).") default: println("Nothing") }
Enjoy!!
If you enjoyed reading this post, please share and recommend it so others can find it 💚💚💚💚💚💚 !!!!
Passing the function’s final argument to a closure expression is declared with the help of ‘Trailing Closures’. It is written outside the function () with {}. Its usage is needed when it is not possible to write the function inline on a single line.
reversed = sorted(names) { $0 > $1}
where {$0 > $1} are represented as trailing closures declared outside (names).
import Foundation
var letters = ["North", "East", "West", "South"]
let twoletters = letters.map({
(state: String) -> String in
return state.substringToIndex(advance(state.startIndex, 2)).uppercaseString
})
let stletters = letters.map() {
$0.substringToIndex(advance($0.startIndex, 2)).uppercaseString
}
print(stletters)
When we run the above program using playground, we get the following result −
Understanding Event Handling, Responders, and the Responder Chain
Learn how events are propagated through your app and how you handle them.
Overview
Apps receive and handle events using responder objects. A responder object is any instance of the UIResponder class, and common subclasses include UIView, UIViewController, and UIApplication. Responders receive the raw event data and must either handle the event or forward it to another responder object. When your app receives an event, UIKit automatically directs that event to the most appropriate responder object, known as the first responder. Unhandled events are passed from responder to responder in the active responder chain, which is a dynamic configuration of your app’s responder objects. There is no single responder chain within your app. UIKit defines default rules for how objects are passed from one responder to the next, but you can always change those rules by overriding the appropriate properties in your responder objects.Figure 1 shows the default responder chains in an app whose interface contains a label, a text field, a button, and two background views. If the text field does not handle an event, UIKit sends the event to the text field’s parent UIView object, followed by the root view of the window. From the root view, the responder chain diverts to the owning view controller before directing the event to the window.(참조 https://youtu.be/i01OwhToIrk) If the window does not handle the event, UIKit delivers the event to the UIApplicationobject, and possibly to the app delegate if that object is an instance of UIResponder and not already part of the responder chain.
Responder chains in an app
Determining the First Responder for an Event
For every type of event, UIKit designates a first responder and sends the event to that object first. The first responder varies based on the type of event.
Touch events
The first responder is the view in which the touch occurred.
Press events
The first responder is the responder that has focus.
Shake-motion events
The first responder is the object that you (or UIKit) designate as the first responder.
Remote-control events
The first responder is the object that you (or UIKit) designate as the first responder.
Editing menu messages
The first responder is the object that you (or UIKit) designate as the first responder.
Note
Motion events related to the accelerometers, gyroscopes, and magnetometer do not follow the responder chain. Instead, Core Motion delivers those events directly to the object you designate. For more information, see Core Motion Framework
Controls communicate directly with their associated target object using action messages. When the user interacts with a control, the control calls the action method of its target object—in other words, it sends an action message to its target object. Action messages are not events, but they may still take advantage of the responder chain. When the target object of a control is nil, UIKit starts from the target object and walks the responder chain until it finds an object that implements the appropriate action method. For example, the UIKit editing menu uses this behavior to search for responder objects that implement methods with names like cut(_:), copy(_:), or paste(_:).
If a view has an attached gesture recognizer, the gesture recognizer receives touch and press events before the view receives them. If all of the view’s gesture recognizers fail to recognize their gestures, the events are passed to the view for handling. If the view does not handle them, UIKit passes the events up the responder chain. For more information about using gesture recognizer’s to handle events, see Handling UIKit Gestures.
Determining Which Responder Contained a Touch Event
UIKit uses view-based hit-testing to determine where touch events occur. Specifically, UIKit compares the touch location to the bounds of view objects in the view hierarchy. The hitTest(_:with:)method of UIView walks the view hierarchy, looking for the deepest subview that contains the specified touch. That view becomes the first responder for the touch event.
Note
If a touch location is outside of a view’s bounds, the hitTest(_:with:) method ignores that view and all of its subviews. As a result, when a view’s clipsToBoundsproperty is false, subviews outside of that view’s bounds are not returned even if they happen to contain the touch. For more information about the hit-testing behavior, see the discussion of the hitTest(_:with:) method in UIView.
UIKit permanently assigns each touch to the view that contains it. UIKit creates each UITouch object when the touch first occurs, and it releases that touch object only after the touch ends. As the touch location or other parameters change, UIKit updates the UITouch object with the new information. The only property that does not change is the containing view. Even when the touch location moves outside the original view, the value in the touch’s view property does not change.
Altering the Responder Chain
You can alter the responder chain by overriding the next property of your responder objects. When you do this, the next responder is the object that you return.
Many UIKit classes already override this property and return specific objects.
UIView objects. If the view is the root view of a view controller, the next responder is the view controller; otherwise, the next responder is the view’s superview.
If the view controller’s view is the root view of a window, the next responder is the window object. If the view controller was presented by another view controller, the next responder is the presenting view controller.
UIApplication object. The next responder is the app delegate, but only if the app delegate is an instance of UIResponder and is not a view, view controller, or the app object itself.