Search This Blog

Saturday, February 17, 2018

The Heavy Pill Task. Solution in Swift

There are 20 bottles of pills. 19 bottles have pills of weight 1.0 gram, but one has pills of weight 1.1 grams. How to find heavy bottle? There is constraint: you can make only one measurement.

In order to find a bottle with heavy pills let's take 1 pill from a first bottle 2 from the second and so on up to 20. Also, we know in advance the total weight of pills in this calculation if in all bottles the pills weigh 1 gram. It will be 1 + 2 + 3 + ... + 20 = 210 grams. Thus, we need to deduct the summary weight of all normal pills from the summary weight of pills with heavy pills and divide by the difference between the weight of the heavy and normal pills(1.1 - 1 = 0.1 grams).

So, formula is

bottleNumber = (summaryWeightWithHeavy - summaryWeightNormal) / (diff)

where summaryWeightNormal = 210 grams, diff = 0.1 grams

bottleNumber = (summaryWeightWithHeavy - 210) / 0.1

Coding algorithm for checking solution and formula:

  1. Generate random number for heavy bottle
  2. In loop from 1 to number of bottles we calculate normal weight and "heavy" weight(when one of bottles has heavy pills)
  3. According to our formula: We take the normal total weight from the heavy total weight and divide this difference by the difference between the weights for one pill
  4. Check that found bottle number equals initial bottle number


Source code
import Foundation

let bottlesCount = 20
let normalPill = 1.0
let heavyPill = 1.1
let diff = heavyPill - normalPill

let heavyBottleNumber = 1 + Int(arc4random_uniform(UInt32(bottlesCount)))
print(heavyBottleNumber)

var normalWeight = 0.0
var heavyWeight = 0.0

for i in 1...bottlesCount {
    normalWeight += Double(i)
    if i == heavyBottleNumber {
        heavyWeight += (Double(i) * heavyPill)
    } else {
        heavyWeight += Double(i)
    }
}


let result = Int(round((heavyWeight - normalWeight) / diff))
print(result)
assert(heavyBottleNumber == result, "failed")

Friday, February 9, 2018

iOS Swift. Difference between leftAnchor and leadingAnchor

When we working with constraint programatically we can have two options for left side: leadingAnchor and leftAnchor, the same for right side: rightAnchor and trailingAnchor.

What is the difference between this anchors?

for left side
self.view.leftAnchor
and
self.view.leadingAnchor

for right side:
self.view.rightAnchor
and
self.view.trailingAnchor

leftAnchor and rightAnchor are strongly fixed and always depend on the left and right sides of the screen. leadingAnchor and trailingAnchor are flexible and depend on the device locale. For locales, where the spelling is from left to right this anchors can be used interchangeably(left with leading and right with trailing). For locales, where the spelling is from right to left leadingAnchor will depend on the right side and trailingAnchor will depend the left side.

For example, you have a screen on which the label is located on the left and textfield on the right for the locale where the writing is from left to right. For a locale where the spelling is from right to left label will be located right and textfield on the left.

You should always use leadingAnchor and trailingAnchor instead of leftAnchor and rightAnchor unless you have special requirements that say that the interface elements are always depend on the left or on the right.

If you want the interface element to be on the screen on the left or right depending on the locale, then use leadingAnchor and trailingAnchor, respectively.

If you want the interface element to always be located on the left or right, regardless of the locale, then use leftAnchor and rightAnchor , respectively.

Tuesday, February 6, 2018

iOS Swift. All ways to unwrap optional

There I want to enumerate all possible ways to unwrap optional variables that possible in Swift.

  1. Force Unwrapping
  2. Check for nil (with !=) and Force Unwrapping
  3. Ternary Operator
  4. if let Construction or Single Optional Binding
  5. Multiple Optional Binding
  6. Guard Operator
  7. Nil Coalescing Operator
  8. Switch Operator
  9. Optional Chaining

Let's review each of them.


Force Unwrapping


When you have optional and you are sure that this optional has a value you always can just use force unwrapping with ! (exclamation point operator). But it always for your responsibility use this because there can be situations when optional will have no value and force unwrapping will produce error and app crashing.
let dict = [1: "Jack", 2: "John", 9: "Kate", 77: "Charlie"]
let name1 = dict[1]
let name4 = dict[4]
print(name1!) // "Jack"
print(name4!) // Fatal error: Unexpectedly found nil while unwrapping an Optional value

Check for nil


But there is solution for ensure from errors when using force unwrapping - just check optional for nil before that.
let dict = [1: "Jack", 2: "John", 9: "Kate", 77: "Charlie"]

print(dict[1]) // Optional("Jack")
print(dict[4]) // nil

func getName(for index: Int) -> String {
    if dict[index] != nil {
        return dict[index]!
    }
    return "No name for such index"
}

print(getName(for: 1)) // "Jack"
print(getName(for: 4)) // No name for such index

Ternary Operator


The same check for nil can be done with ternary operator.
let dict = [1: "Jack", 2: "John", 9: "Kate", 77: "Charlie"]

print(dict[1]) // Optional("Jack")
print(dict[4]) // nil

func getName(for index: Int) -> String {
    return dict[index] != nil ? dict[index]! : "No name for such index"
}

print(getName(for: 1)) // "Jack"
print(getName(for: 4)) // No name for such index

if let Construction or Optional Binding


This construction if let allows you safety unwrap optional value. If optional has value then this value will be unwrapped to constant/variable. Unwrapped variable/constant will be available only in scope inside this if let statement.
let dict = [1: "Jack", 2: "John", 9: "Kate", 77: "Charlie"]

print(dict[1]) // Optional("Jack")
print(dict[4]) // nil

func getName(for index: Int) -> String {
    if let name = dict[index] {
        return name
    }
    return dict[index] ?? "No name for such index"
}

print(getName(for: 1)) // "Jack"
print(getName(for: 4)) // No name for such index

Multiple Optional binding


There can be optional property of optional object, so you can do some chaining of if let statements. All this if let statements can be written in on line with one if and with commas. Every next statement will be executed only if previous value is unwrapped.
struct A {
    let dict = [1: "Jack", 2: "John", 9: "Kate", 77: "Charlie"]
    func getName(for index: Int) -> String? {
        return dict[index]
    }
}

struct B {
    var names: A?
    
    init() {
        self.names = A()
    }
}

let b: B? = B()

if let b = b {
    if let names = b.names {
        if let name = names.getName(for: 1) {
            print(name) // Jsck
        }
    }
}

if let b = b, let names = b.names, let name = names.getName(for: 1) {
    print(name) // Jack
}

Guard Operator


Guard operator or "Early Exit" check that optional has value and can be unwrapped. If optional has no value then else statement will be executed. Unwrapped value will be available in scope next to guard, opposite to if let statement.
let dict = [1: "Jack", 2: "John", 9: "Kate", 77: "Charlie"]

print(dict[1]) // Optional("Jack")
print(dict[4]) // nil

func getName(for index: Int) -> String {
    guard let name = dict[index] else {
        return "No name for such index"
    }
    return name
}

print(getName(for: 1)) // "Jack"
print(getName(for: 4)) // No name for such index

Nil Coalescing Operator or ??


Special operator ?? works following way: if there is a value in optional then this value will be return else default value will be return.
let dict = [1: "Jack", 2: "John", 9: "Kate", 77: "Charlie"]

print(dict[1]) // Optional("Jack")
print(dict[4]) // nil

func getName(for index: Int) -> String {
    return dict[index] ?? "No name for such index"
}

print(getName(for: 1)) // "Jack"
print(getName(for: 4)) // No name for such index

Switch Operator


We can use switch operator for unwrapping optionals because if we open source code of Optional we can see that Optional is an enum with 2 cases: none and some.
public enum Optional<Wrapped> : ExpressibleByNilLiteral {
    case none
    case some(Wrapped)
}

In case of .none - there is no value (it means nil). In case of .some - there is a value that we can use and this value will be unwrapped.
let dict = [1: "Jack", 2: "John", 9: "Kate", 77: "Charlie"]

func getName(for index: Int) -> String {
    let name =  dict[index]
    switch name {
    case .some(let value):
        return value
    case .none:
        return "No name for such index"
    }
}

print(getName(for: 1)) // Jack
print(getName(for: 4)) // No name for such index

Optional Chaining


In some cases optional instance of struct or class can have optional properties. So, when we need to get optional property of optional object it is a chain of optionals. Every next optional value will be unwrap only if previous is can be unwrapped. For, example
b?.names?.getName(for: 1)?.count
Property count will be getting only if b can be unwrapped, names can be unwrapped and value which will be returned by getNames() can be unwrapped too. If any of values in chain cannot be unwrapped then property count will be nil.
struct A {
    let dict = [1: "Jack", 2: "John", 9: "Kate", 77: "Charlie"]
    func getName(for index: Int) -> String? {
        return dict[index]
    }
}

struct B {
    var names: A?
    
    init() {
        self.names = A()
    }
}

let b: B? = B()
b?.names?.getName(for: 4)?.count

print(b?.names?.getName(for: 1)?.count) // Optional(4) because "Jack" has 4 letters
print(b?.names?.getName(for: 4)?.count) // nil because no name for such index

Friday, February 2, 2018

iOS Swift. Check if keyboard is visible

How we can get is keyboard is shown or hidden currently in our app?

Keyboard is shown

That is it. Simple solution, we just need to add observer for keyboard notification.
override func viewDidLoad() {
    super.viewDidLoad()
        
    NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardShow),
                                           name: Notification.Name.UIKeyboardWillShow, object: nil)       
}
    
@objc func handleKeyboardShow(notification: Notification) {
    print("Keyboard will show")
}
This observer only works for event when keyboard will be shown, there is another observer for event when keyboard will be hidden.

override func viewDidLoad() {
    super.viewDidLoad()
        
    NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardShow),
                                           name: Notification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardHide),
                                           name: Notification.Name.UIKeyboardWillHide, object: nil)
}
    
@objc func handleKeyboardShow(notification: Notification) {
    print("Keyboard will show")
}
    
@objc func handleKeyboardHide(notification: Notification) {
    print("Keyboard will hide")
}
But there is a lot more thing beside this. And I want to tell you about some of them.