Last active
December 3, 2016 22:37
-
-
Save Skorch/1005d49ad5526fe917fea7ebfdb77625 to your computer and use it in GitHub Desktop.
A protocol based solution to capturing analytics in Swift 3 v2
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// AnalyticsSegmentIOPublisher.swift | |
// DropShift | |
// | |
// Created by Drew Beaupre on 2016-10-03. | |
// Copyright © 2016 drew.beaupre. All rights reserved. | |
// | |
import Foundation | |
import Analytics | |
class AnalyticsSegmentIOPublisher{ | |
private let serialQueue = DispatchQueue(label: "com.drew.beaupre.dropshift.analytics.segment") | |
static let sharedInstance: AnalyticsSegmentIOPublisher = { | |
return AnalyticsSegmentIOPublisher() | |
}() | |
func handleEvent(eventType: EventType, eventProperties: [String: Any]?) -> Void{ | |
serialQueue.async{ | |
SEGAnalytics.shared().track(eventType.segmentName, properties: eventProperties) | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// EventType+GameEnded.swift | |
// DropShift | |
// | |
// Created by Drew Beaupre on 2016-10-07. | |
// Copyright © 2016 drew.beaupre. All rights reserved. | |
// | |
import Foundation | |
extension EventType{ | |
struct GameEnded: PublishableEvent{ | |
//MARK PropertyNames | |
private enum FieldNames: String{ | |
case opponentType = "Opponent Type", | |
winningPlayer = "Winning Player", | |
moveCounts = "Number of Moves", | |
value = "value" | |
} | |
//MARK Properties | |
var opponentType: PlayerType | |
var winnningPlayer: GamePlayer | |
var moveCount: Int | |
//MARK:- PublishableEvent | |
var eventProperties: [String: Any]? { | |
return [ | |
FieldNames.opponentType.rawValue: opponentType.description, | |
FieldNames.winningPlayer.rawValue: winnningPlayer.description, | |
FieldNames.moveCounts.rawValue: MoveCountCategory(fromInt: moveCount).description, | |
FieldNames.value.rawValue: moveCount | |
] | |
} | |
//MARK:- SubscribableEvent | |
static var eventType: EventType{ | |
return .gameEnded | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// EventType+GameStarted.swift | |
// DropShift | |
// | |
// Created by Drew Beaupre on 2016-10-03. | |
// Copyright © 2016 drew.beaupre. All rights reserved. | |
// | |
import Foundation | |
extension EventType{ | |
struct GameStarted: PublishableEvent{ | |
//MARK PropertyNames | |
private enum FieldNames: String{ | |
case opponentType | |
} | |
//MARK Properties | |
private(set) var opponentType: PlayerType | |
//MARK:- PublishableEvent | |
var eventProperties: [String: Any]? { | |
return [ | |
FieldNames.opponentType.rawValue: opponentType.description | |
] | |
} | |
//MARK:- SubscribableEvent | |
static var eventType: EventType{ | |
return .gameStarted | |
} | |
} | |
} | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// EventType+SurveyAnswer.swift | |
// DropShift | |
// | |
// Created by Drew Beaupre on 2016-10-18. | |
// Copyright © 2016 drew.beaupre. All rights reserved. | |
// | |
import Foundation | |
extension EventType{ | |
struct SurveyAnswer: PublishableEvent{ | |
//MARK PropertyNames | |
private enum FieldNames: String{ | |
case question, answer | |
} | |
//MARK Properties | |
private(set) var questionText: String | |
private(set) var answerValue: String | |
//MARK:- PublishableEvent | |
var eventProperties: [String: Any]? { | |
return [ | |
FieldNames.question.rawValue: questionText, | |
FieldNames.answer.rawValue: answerValue | |
] | |
} | |
//MARK:- SubscribableEvent | |
static var eventType: EventType{ | |
return .surveyAnswer | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// EventType.swift | |
// DropShift | |
// | |
// Created by Drew Beaupre on 2016-10-03. | |
// Copyright © 2016 drew.beaupre. All rights reserved. | |
// | |
import Foundation | |
enum EventType: String{ | |
case gameStarted = "Game Started" | |
case gameEnded = "Game Ended" | |
case gameReset = "Game Reset" | |
case surveyAnswer = "Survey Answer" | |
init?(notificationName: Notification.Name){ | |
self.init(rawValue: notificationName.rawValue) | |
} | |
static func allEventTypes() -> [EventType]{ | |
return [ | |
.gameStarted, | |
.gameEnded, | |
.gameReset, | |
.surveyAnswer | |
] | |
} | |
} | |
extension EventType{ | |
var notificationName: NSNotification.Name{ | |
return NSNotification.Name(rawValue: self.rawValue) | |
} | |
} | |
extension EventType{ | |
var segmentName: String{ | |
return self.rawValue | |
} | |
var gameAnalyticsName: String{ | |
return self.rawValue.lowercased().replacingOccurrences(of: " ", with: ":") | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// MoveCountCategory.swift | |
// DropShift | |
// | |
// Created by Drew Beaupre on 2016-10-07. | |
// Copyright © 2016 drew.beaupre. All rights reserved. | |
// | |
import Foundation | |
internal enum MoveCountCategory: String, CustomStringConvertible{ | |
case invalid = "invalid" | |
case lessThanEight = "< 8" | |
case eightToFourteen = "8 - 14" | |
case fifteenToTwenty = "15 - 20" | |
case twentyOneToThirty = "21 - 30" | |
case greaterThan30 = "> 30" | |
init(fromInt value: Int){ | |
switch value{ | |
case 0..<8: self = .lessThanEight | |
case 8...14: self = .eightToFourteen | |
case 15...20: self = .fifteenToTwenty | |
case 21...30: self = .twentyOneToThirty | |
case 31...Int.max: self = .greaterThan30 | |
default: self = .invalid | |
} | |
} | |
var description: String{ | |
return self.rawValue | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// PublishableEvent.swift | |
// DropShift | |
// | |
// Created by Drew Beaupre on 2016-10-03. | |
// Copyright © 2016 drew.beaupre. All rights reserved. | |
// | |
import Foundation | |
protocol PublishableEvent{ | |
static var eventType: EventType {get} | |
var eventProperties: [String: Any]? { get } | |
} | |
extension PublishableEvent { | |
func publish() -> Void{ | |
AnalyticsSegmentIOPublisher.sharedInstance.handleEvent(eventType: Self.eventType, eventProperties: eventProperties) | |
} | |
var eventProperties: [String: Any]? { | |
return [String: Any]() | |
} | |
} | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
The goal is to make tracking an event as simple and safe as possible. | |
Each event type is namespaced within the EventType enum for discoverability | |
Each event type explicitly lists its necessary property values | |
Each event type handles all mapping, publishing, concurrency | |
Event prorties are strongly typed | |
*/ | |
EventType.GameStarted(opponentType: opponentPlayerType).publish() | |
EventType.GameEnded(opponentType: opponentPlayerType, winnningPlayer: winners.first!.gamePlayer, moveCount: moves).publish() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
A protocol based solution to capturing analytics in Swift 3
There were two main goals for this solution:
Tracking an event as simple and safe as possible.
Creating new event types should be simple
Events should support being complex if necessary