Search This Blog

Saturday, September 23, 2017

iOS CALayer and how to use it


Description

Every UIView has CALayer. Visual representation of UIView is defined by attributes of CALayer property. You can setup many visual attributes of the view through the CALayer property: 
  • rounded corners
  • borders
  • opacity
  • background color
  • image content
  • shadows
  • and others
So, UIView wraps CALayer and all visual changes that you send to UIView get forward to CALayer object. UIView has one root CALayer and this root layer can contain sublayers. 

Code 

Rounded Corners
// make rounded corners
self.customView.layer.cornerRadius = 16

Borders
// add borders
self.customView.layer.borderColor = UIColor.black.cgColor
self.customView.layer.borderWidth = 3

Shadows
// add shadows
self.customView.layer.shadowOffset = CGSize(width: 6, height: 6)
self.customView.layer.shadowOpacity = 0.8
self.customView.layer.shadowRadius = 6
self.customView.layer.shadowColor = UIColor.black.cgColor

Image content
// add image content
self.customView.layer.contents = UIImage(named: "cats-eyes")?.cgImage
self.customView.layer.contentsGravity = kCAGravityResizeAspectFill
self.customView.layer.masksToBounds = true

Opacity
// opacity background
self.customView.layer.backgroundColor = UIColor.red.cgColor
self.customView.layer.opacity = 0.5

Screens



CALayer Demo project on GitHub


How reverse String in Swift

There is simple way to make reversed string

import UIKit

var str = "Hello, playground"

// First way
print(String(str.reversed()))

//Second way
var charArray: [Character] = [Character]()
for ch in str {
    charArray.append(ch)
}

var reversedArray: [Character] = [Character]()

for i in (0..<str.count).reversed() {
    reversedArray.append(charArray[i])
}

print(String(reversedArray))

Friday, September 22, 2017

NSCoding Protocol and how to use it

Implementing NSCoding Protocol


NSCoding is simple protocol with two methods. If we want to save our custom class with all its fields we need to implement this protocol. Class that conform to NSCoding protocol can be serialized and deserialized into data.

public func encode(with aCoder: NSCoder)

public init?(coder aDecoder: NSCoder)

Implementation of our custom class that confirm NSCoding protocol
import Foundation
import UIKit

class AppSettings: NSObject, NSCoding {
    
    var themeColor: UIColor
    var userName: String
    var isActivated: Bool
    var lastActivityDate: Date
    var count: Int
    
    func encode(with aCoder: NSCoder) {
        aCoder.encode(self.themeColor, forKey: "themeColor")
        aCoder.encode(self.userName, forKey: "userName")
        aCoder.encode(self.isActivated, forKey: "isActivated")
        aCoder.encode(self.lastActivityDate, forKey: "lastActivityDate")
        aCoder.encode(self.count, forKey: "count")
    }
    
    required convenience init?(coder aDecoder: NSCoder) {
        
        guard let themeColor = aDecoder.decodeObject(forKey: "themeColor") as? UIColor,
            let userName = aDecoder.decodeObject(forKey: "userName") as? String,
            let lastActivityDate = aDecoder.decodeObject(forKey: "lastActivityDate") as? Date else {
                return nil
        }
        
        self.init(themeColor: themeColor,
                  userName: userName,
                  isActivated: aDecoder.decodeBool(forKey: "isActivated"),
                  lastActivityDate: lastActivityDate,
                  count: aDecoder.decodeInteger(forKey: "count"))
    }
    
    init(themeColor: UIColor, userName: String, isActivated: Bool, lastActivityDate: Date, count: Int) {
        self.themeColor = themeColor
        self.userName = userName
        self.lastActivityDate = lastActivityDate
        self.isActivated = isActivated
        self.count = count
    }
    
}


Using NSKeyedArchiver and NSKeyedUnrachiver we can implement saving and loading of data that we get from serizlization/deserizlization of our object (that is instance of custom class that confirm NSCoding protocol)

Save object with NSKeyedArchiver

let data = NSKeyedArchiver.archivedData(withRootObject: self.appSettings)
let userDefaults = UserDefaults.standard
userDefaults.set(data, forKey: "appSettings")

Load object with NSKeyedUnrachiver

let userDafaults = UserDefaults.standard
if let data = userDafaults.object(forKey: "appSettings") as? Data {
    self.appSettings = NSKeyedUnarchiver.unarchiveObject(with: data) as! AppSettings
} else {
    self.appSettings = AppSettings(themeColor: UIColor.red,
                                           userName: "John",
                                           isActivated: true,
                                           lastActivityDate: Date(),
                                           count: 22)
}

Sources

http://nshipster.com/nscoding/
https://habrahabr.ru/company/inetra/blog/185918/
https://itvdn.com/ru/blog/article/it-intriduction-ios-dev-part7

Problems and errors

In order to make NSCoding work you need to declare the super class NSObject.
class AppSettings: NSObject, NSCoding {
    ...
}
Crash when implementing NSCoding in Swift

GitHub

Source code on github