These are the slides of my talk at iOSCon 2017: https://skillsmatter.com/skillscasts/9549-architecting-alive-apps
Our apps are ever more alive. They interact with the rest of the world talking to backends and receiving notifications from them. They get their input from us and from other sensors. They are even aware of the location of the device they run in, or its position. But, in our IoT world, they may also detect presence in a room, get the temperature of it, or change the color of its lights.
Sadly enough, many of the apps available today with those capabilities have some architectural limitations:
Many of them are written in a way that is really dependent on a specific hardware.
Some restrict their use cases to whatever is provided by the hardware devices.
And almost all of them expect having a connection with the real device as the only way to test if they work properly.
However, we can also use an advanced architecture, like the Clean Architecture, to create a beautiful, scalable, testable, and robust application. Join Jorge and he will share with you how you can do it!
This is a "Code or it didn't happen" (TM) talk.
39. #Swift3CA
From Date to JSON
★ MQTT messages
contained JSON
★ firetime is a JSON
format date
let formatter =
ISO8601DateFormatter()
let command: [ String: String ] = [
"firetime":
formatter.string(from: fireDate),
"type": type.mqttActionType(),
]
let jsonData = try!
JSONSerialization.data(withJSONObject
: command, options:
JSONSerialization.WritingOptions())
as Data
40. #Swift3CA
Picky with Dates
★ HomeKit
HMTimeTrigger only
accepts times with
seconds = 0
private func fixFireDate(_ fireDate:
Date) !-> Date {
let calendar = Calendar.current
let fixedFireDate =
calendar.nextDate(after: fireDate,
matching: DateComponents(second: 0),
matchingPolicy: .nextTime)!
return fixedFireDate
}
41. #Swift3CA
Browse HomeKit
★ HomeKit offers several
abstractions in a
hierarchy
• Homes
• Rooms
• Accessories
• Services
• Triggers
★ Extract what you need
class HomeKitColorLight: NSObject, LightController
{
var delegate: LightControllerDelegate?
fileprivate let homeManager: HMHomeManager
fileprivate var primaryHome: HMHome?
func homeManagerDidUpdateHomes(_ manager:
HMHomeManager) {
primaryHome = homeManager.primaryHome
delegate!?.lightControllerReady(self)
}
private func searchFirstColorLight() !->
HMService? {
let lightbulbs =
primaryHome!?.servicesWithTypes([HMServiceTypeLightb
ulb])
let colorLightbulb = lightbulbs!?.first
{ (service) in
let characteristics =
service.characteristics.filter { (characteristic)
in
return
characteristic.characteristicType !==
HMCharacteristicTypeHue
}
return characteristics.count > 0
}
return colorLightbulb
}
}
42. #Swift3CA
Look for Events
★ EventKit allows
multiple calendars
★ Avoid that
complexity
fileprivate func fetchMeetingCalendar() {
guard status !== .ready else { return }
let calendars =
eventStore.calendars(for: .event)
let calendar = calendars.filter { $0.title
!== meetingCalendarTitle } .first
if let calendar = calendar {
meetingCalendar = calendar
} else {
meetingCalendar =
EKCalendar(for: .event, eventStore:
eventStore)
if let meetingCalendar =
meetingCalendar {
meetingCalendar.title =
meetingCalendarTitle
meetingCalendar.source =
eventStore.defaultCalendarForNewEvents.source
do {
try
eventStore.saveCalendar(meetingCalendar,
commit: true)
} catch let error as NSError {
NSLog("Error: (error)")
}
}
}
}
43. #Swift3CA
Authorization
★ EventKit requires
Authorization to
access the data
class EventKitEventProvider {
enum Status {
case ready, accessDenied, unknown
}
let eventStore: EKEventStore
var status = Status.unknown
init() {
eventStore = EKEventStore()
checkAccessToEvents()
fetchMeetingCalendar()
}
private func checkAccessToEvents() {
switch
EKEventStore.authorizationStatus(for: .event) {
case .authorized:
status = .ready
case .notDetermined: !// First time access
requestAccessToEvents()
case .denied, .restricted:
status = .accessDenied
}
}
private func requestAccessToEvents() {
eventStore.requestAccess(to: .event)
{ (granted: Bool, error: Error?) in
!// …
}
}
}
44. #Swift3CA
extension LightControllerAction {
func homeKitColor() !-> UIColor {
let color: UIColor
switch(self) {
case .start: color = UIColor.green
case .warn: color =
UIColor.orange
case .end: color = UIColor.red
case .off: color = UIColor.black
}
return color
}
func sceneName() !-> String {
let name: String
switch(self) {
case .start: name = "Go green"
case .warn: name = "Go orange"
case .end: name = "Go red"
case .off: name = "Go off"
}
return name
}
}
Extend like a Boss
extension LightControllerAction {
func mqttActionType() !-> String {
let action: String
switch self {
case .start:
action = "start"
case .warn:
action = "warn"
case .end:
action = "end"
case .off:
action = "off"
}
return action
}
}
46. #Swift3CA
Recap
★ IoT is cool!
★ Advanced architectures can also be applied
to apps with frameworks
★ Use abstractions
★ YES, I mean it: Use abstractions