Skip to content

Commit b1db4b0

Browse files
authored
Remove various IUOs, force unwraps, and force casts (#89)
2 parents e4dcfa8 + f6876d0 commit b1db4b0

11 files changed

+111
-64
lines changed

Diff for: Demo/ParselyDemo.xcodeproj/project.pbxproj

+4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
/* Begin PBXBuildFile section */
1010
2A1F02DDE91E502E3B49AFAB /* StorageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A1F03819E4FAF1F979D5926 /* StorageTests.swift */; };
11+
3F0B192F2A8DD03B0012C731 /* ParselyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F0B192D2A8DCFBC0012C731 /* ParselyTests.swift */; };
1112
3F147F8F29EF8CA100752DFB /* Nimble in Frameworks */ = {isa = PBXBuildFile; productRef = 3F147F8E29EF8CA100752DFB /* Nimble */; };
1213
3F147F9529EF965500752DFB /* ParselyAnalytics in Frameworks */ = {isa = PBXBuildFile; productRef = 3F147F9429EF965500752DFB /* ParselyAnalytics */; };
1314
3F147F9729EF96EE00752DFB /* ParselyAnalytics in Frameworks */ = {isa = PBXBuildFile; productRef = 3F147F9629EF96EE00752DFB /* ParselyAnalytics */; };
@@ -57,6 +58,7 @@
5758

5859
/* Begin PBXFileReference section */
5960
2A1F03819E4FAF1F979D5926 /* StorageTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StorageTests.swift; sourceTree = "<group>"; };
61+
3F0B192D2A8DCFBC0012C731 /* ParselyTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParselyTests.swift; sourceTree = "<group>"; };
6062
3F147F9129EF962200752DFB /* AnalyticsSDK-iOS */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = "AnalyticsSDK-iOS"; path = ..; sourceTree = "<group>"; };
6163
3FCAFC8B29E9775A00BC9360 /* UnitTests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = UnitTests.xctestplan; sourceTree = "<group>"; };
6264
AA73AAAE2242C1F10089BF1D /* ParselyTestCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParselyTestCase.swift; sourceTree = "<group>"; };
@@ -176,6 +178,7 @@
176178
B205889E220CB72A00476E27 /* RequestBuilderTests.swift */,
177179
B2FC40BF221CC43200C70806 /* MetadataTests.swift */,
178180
AA73AAAE2242C1F10089BF1D /* ParselyTestCase.swift */,
181+
3F0B192D2A8DCFBC0012C731 /* ParselyTests.swift */,
179182
3FCAFC8B29E9775A00BC9360 /* UnitTests.xctestplan */,
180183
);
181184
name = Tests;
@@ -314,6 +317,7 @@
314317
files = (
315318
B2FC40C0221CC43200C70806 /* MetadataTests.swift in Sources */,
316319
F410D63121061D7800DB3EBE /* PixelTests.swift in Sources */,
320+
3F0B192F2A8DD03B0012C731 /* ParselyTests.swift in Sources */,
317321
F4BF866E2190DB4A00BD3867 /* VideoTests.swift in Sources */,
318322
AA73AAAF2242C1F10089BF1D /* ParselyTestCase.swift in Sources */,
319323
F441A55C20F3B8BF009B556E /* EventQueueTests.swift in Sources */,

Diff for: Sources/EngagedTime.swift

+3-3
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,17 @@ class EngagedTime: Sampler {
1717
}
1818
let roundedSecs: Int = Int(data.accumulatedTime)
1919
let totalMs: Int = Int(data.totalTime.milliseconds())
20-
let eventArgs = data.eventArgs!
20+
let eventArgs = data.eventArgs
2121

2222
let event = Heartbeat(
2323
"heartbeat",
24-
url: eventArgs["url"] as! String,
24+
url: eventArgs["url"] as? String ?? "URL_MISSING",
2525
urlref: eventArgs["urlref"] as? String,
2626
inc: roundedSecs,
2727
tt: totalMs,
2828
metadata: eventArgs["metadata"] as? ParselyMetadata,
2929
extra_data: eventArgs["extra_data"] as? Dictionary<String, Any>,
30-
idsite: (eventArgs["idsite"] as! String)
30+
idsite: eventArgs["idsite"] as? String
3131
)
3232

3333
parselyTracker.track.event(event: event)

Diff for: Sources/Event.swift

+20-2
Original file line numberDiff line numberDiff line change
@@ -105,10 +105,28 @@ class Heartbeat: Event {
105105
var tt: Int
106106
var inc: Int
107107

108-
init(_ action: String, url: String, urlref: String?, inc: Int, tt: Int, metadata: ParselyMetadata?, extra_data: Dictionary<String, Any>?, idsite: String = "") {
108+
init(
109+
_ action: String,
110+
url: String,
111+
urlref: String?,
112+
inc: Int,
113+
tt: Int,
114+
metadata: ParselyMetadata?,
115+
extra_data: Dictionary<String, Any>?,
116+
idsite: String?
117+
) {
109118
self.tt = tt
110119
self.inc = inc
111-
super.init(action, url: url, urlref: urlref, metadata: metadata, extra_data: extra_data, idsite: idsite)
120+
121+
super.init(
122+
action,
123+
url: url,
124+
urlref: urlref,
125+
metadata: metadata,
126+
extra_data: extra_data,
127+
// empty string seems a weird default, but is what we had in the code before this comment was written
128+
idsite: idsite ?? ""
129+
)
112130
}
113131

114132
override func toDict() -> Dictionary<String, Any> {

Diff for: Sources/Metadata.swift

+16-16
Original file line numberDiff line numberDiff line change
@@ -44,29 +44,29 @@ public class ParselyMetadata {
4444
func toDict() -> Dictionary<String, Any> {
4545
var metas: Dictionary<String, Any> = [:]
4646

47-
if canonical_url != nil {
48-
metas["link"] = canonical_url!
47+
if let canonical_url {
48+
metas["link"] = canonical_url
4949
}
50-
if pub_date != nil {
51-
metas["pub_date"] = String(format:"%i", pub_date!.millisecondsSince1970)
50+
if let pub_date {
51+
metas["pub_date"] = String(format:"%i", pub_date.millisecondsSince1970)
5252
}
53-
if title != nil {
54-
metas["title"] = title!
53+
if let title {
54+
metas["title"] = title
5555
}
56-
if authors != nil {
57-
metas["authors"] = authors!
56+
if let authors {
57+
metas["authors"] = authors
5858
}
59-
if image_url != nil {
60-
metas["image_url"] = image_url!
59+
if let image_url {
60+
metas["image_url"] = image_url
6161
}
62-
if section != nil {
63-
metas["section"] = section!
62+
if let section {
63+
metas["section"] = section
6464
}
65-
if tags != nil {
66-
metas["tags"] = tags!
65+
if let tags {
66+
metas["tags"] = tags
6767
}
68-
if duration != nil {
69-
metas["duration"] = duration!
68+
if let duration {
69+
metas["duration"] = duration
7070
}
7171

7272
return metas

Diff for: Sources/ParselyTracker.swift

+2-5
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,7 @@ public class Parsely {
88
public var apikey = ""
99
public var secondsBetweenHeartbeats: TimeInterval? {
1010
get {
11-
if let secondsBtwnHeartbeats = config["secondsBetweenHeartbeats"] as! TimeInterval? {
12-
return secondsBtwnHeartbeats
13-
}
14-
return nil
11+
config["secondsBetweenHeartbeats"] as? TimeInterval
1512
}
1613
}
1714
public static let sharedInstance = Parsely()
@@ -232,7 +229,7 @@ public class Parsely {
232229
let events = eventQueue.get()
233230
os_log("Got %s events", log: OSLog.tracker, type:.debug, String(describing: events.count))
234231
let request = RequestBuilder.buildRequest(events: events)
235-
HttpClient.sendRequest(request: request!, queue: eventProcessor) { error in
232+
HttpClient.sendRequest(request: request, queue: eventProcessor) { error in
236233
if let error = error as? URLError, error.code == .notConnectedToInternet {
237234
// When offline, return the events to the queue for the next flush().
238235
self.eventQueue.push(contentsOf: events)

Diff for: Sources/RequestBuilder.swift

+14-12
Original file line numberDiff line numberDiff line change
@@ -24,25 +24,26 @@ class RequestBuilder {
2424
return platform
2525
}
2626

27-
internal static func getUserAgent() -> String {
28-
if userAgent == nil {
27+
static func getUserAgent() -> String {
28+
guard let userAgent else {
2929
var appDescriptor: String = ""
30-
if let appName = Bundle.main.infoDictionary?["CFBundleName"] as? String {
31-
if let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String {
32-
appDescriptor = String(format: "%@/%@", appName, appVersion)
33-
}
30+
if let appName = Bundle.main.infoDictionary?["CFBundleName"] as? String,
31+
let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String {
32+
appDescriptor = String(format: "%@/%@", appName, appVersion)
3433
}
3534
let osDescriptor = String(format: "iOS/%@", UIDevice.current.systemVersion)
3635
let hardwareString = getHardwareString()
3736
let userAgentString = String(format: "%@ %@ (%@)", appDescriptor, osDescriptor, hardwareString)
3837
// encode the user agent into latin1 in case there are utf8 characters
3938
let userAgentData = Data(userAgentString.utf8)
40-
userAgent = String(data: userAgentData, encoding: .isoLatin1)
39+
40+
return String(data: userAgentData, encoding: .isoLatin1) ?? "invalid user agent"
4141
}
42-
return userAgent!
42+
43+
return userAgent
4344
}
4445

45-
internal static func buildRequest(events: Array<Event>) -> ParselyRequest? {
46+
static func buildRequest(events: Array<Event>) -> ParselyRequest {
4647
let request = ParselyRequest.init(
4748
url: buildPixelEndpoint(),
4849
headers: buildHeadersDict(events: events),
@@ -52,9 +53,10 @@ class RequestBuilder {
5253
return request
5354
}
5455

55-
internal static func buildPixelEndpoint() -> String {
56-
self._baseURL = "https://p1.parsely.com/mobileproxy"
57-
return self._baseURL!
56+
static func buildPixelEndpoint() -> String {
57+
let endpoint = "https://p1.parsely.com/mobileproxy"
58+
_baseURL = endpoint
59+
return endpoint
5860
}
5961

6062
internal static func buildHeadersDict(events: Array<Event>) -> Dictionary<String, String> {

Diff for: Sources/Sampler.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ struct Accumulator {
1717
var heartbeatTimeout: TimeInterval?
1818
var contentDuration: TimeInterval?
1919
var isEngaged: Bool
20-
var eventArgs: Dictionary<String, Any>?
20+
var eventArgs: Dictionary<String, Any>
2121
}
2222

2323
extension TimeInterval {
@@ -58,7 +58,7 @@ class Sampler {
5858
func trackKey(
5959
key: String,
6060
contentDuration: TimeInterval?,
61-
eventArgs: Dictionary<String, Any>?,
61+
eventArgs: Dictionary<String, Any> = [:],
6262
resetOnExisting: Bool = false
6363
) -> Void {
6464
os_log("Sampler tracked key: %s in class %@", log: OSLog.tracker, type: .debug, key, String(describing: self))

Diff for: Sources/Session.swift

+4-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@ class SessionManager {
2222

2323
if session.isEmpty {
2424
var visitorInfo = visitorManager.getVisitorInfo()
25-
visitorInfo["session_count"] = visitorInfo["session_count"] as! Int + 1
25+
26+
if let previousCount = visitorInfo["session_count"] as? Int {
27+
visitorInfo["session_count"] = previousCount + 1
28+
}
2629

2730
session = [:]
2831
session["session_id"] = visitorInfo["session_count"]

Diff for: Sources/Video.swift

+2-5
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,7 @@ class VideoManager: Sampler {
1616
var trackedVideos: Dictionary<String, TrackedVideo> = [:]
1717

1818
override func sampleFn(key: String) -> Bool {
19-
if trackedVideos[key] == nil {
20-
return false
21-
}
22-
return (trackedVideos[key]?.isPlaying)!
19+
trackedVideos[key]?.isPlaying ?? false
2320
}
2421

2522
override func heartbeatFn(data: Accumulator, enableHeartbeats: Bool) -> Void {
@@ -42,7 +39,7 @@ class VideoManager: Sampler {
4239
tt: totalMs,
4340
metadata: curVideo.eventArgs["metadata"] as? ParselyMetadata,
4441
extra_data: curVideo.eventArgs["extra_data"] as? Dictionary<String, Any>,
45-
idsite: curVideo.eventArgs["idsite"] as! String
42+
idsite: curVideo.eventArgs["idsite"] as? String
4643
)
4744
parselyTracker.track.event(event: event)
4845
os_log("Sent vheartbeat for video %s", log: OSLog.tracker, type:.debug, data.key)

Diff for: Tests/ParselyTests.swift

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import Nimble
2+
@testable import ParselyAnalytics
3+
import XCTest
4+
5+
class ParselyTests: ParselyTestCase {
6+
7+
func testSecondsBetweenHeartbeatsNilByDefault() {
8+
XCTAssertNil(makePareslyTracker().secondsBetweenHeartbeats)
9+
}
10+
11+
func testSecondsBetweenHeartbeatsNilWhenNotInConfigDict() {
12+
let parsely = makePareslyTracker()
13+
parsely.config = ["key": "value"]
14+
15+
XCTAssertNil(parsely.secondsBetweenHeartbeats)
16+
}
17+
18+
func testSecondsBetweenHeartbeatsNilWhenInConfigDictButNotTimeInterval() {
19+
let parsely = makePareslyTracker()
20+
parsely.config = ["secondsBetweenHeartbeats": "not seconds"]
21+
22+
XCTAssertNil(parsely.secondsBetweenHeartbeats)
23+
24+
// Notice that Int doesn't cast to TimeInterval
25+
let parsely2 = makePareslyTracker()
26+
parsely2.config = ["secondsBetweenHeartbeats": 123]
27+
28+
XCTAssertNil(parsely2.secondsBetweenHeartbeats)
29+
}
30+
31+
func testSecondsBetweenHeartbeatsParsesValueFromConfigDict() {
32+
let parsely = makePareslyTracker()
33+
parsely.config = ["secondsBetweenHeartbeats": 123.0]
34+
35+
XCTAssertEqual(parsely.secondsBetweenHeartbeats, TimeInterval(123))
36+
}
37+
}

Diff for: Tests/RequestBuilderTests.swift

+7-18
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,8 @@ class RequestBuilderTests: XCTestCase {
2424
)]
2525
}
2626

27-
func testEndpoint() {
28-
let endpoint = RequestBuilder.buildPixelEndpoint()
29-
XCTAssert(endpoint != "", "buildPixelEndpoint should return a non-empty string")
30-
}
31-
3227
func testBuildPixelEndpoint() {
33-
var expected: String = "https://p1.parsely.com/mobileproxy"
34-
var actual = RequestBuilder.buildPixelEndpoint()
35-
XCTAssert(actual == expected, "buildPixelEndpoint should return the correct URL for the given date")
36-
expected = "https://p1.parsely.com/mobileproxy"
37-
actual = RequestBuilder.buildPixelEndpoint()
38-
XCTAssert(actual == expected, "buildPixelEndpoint should return the correct URL for the given date")
28+
XCTAssertEqual(RequestBuilder.buildPixelEndpoint(), "https://p1.parsely.com/mobileproxy")
3929
}
4030

4131
func testHeaders() {
@@ -48,16 +38,15 @@ class RequestBuilderTests: XCTestCase {
4838
func testBuildRequest() {
4939
let events = makeEvents()
5040
let request = RequestBuilder.buildRequest(events: events)
51-
XCTAssertNotNil(request, "buildRequest should return a non-nil value")
52-
XCTAssert(request!.url.contains("https://p1"),
41+
XCTAssert(request.url.contains("https://p1"),
5342
"RequestBuilder.buildRequest should return a request with a valid-looking url attribute")
54-
XCTAssertNotNil(request!.headers,
43+
XCTAssertNotNil(request.headers,
5544
"RequestBuilder.buildRequest should return a request with a non-nil headers attribute")
56-
XCTAssertNotNil(request!.headers["User-Agent"],
45+
XCTAssertNotNil(request.headers["User-Agent"],
5746
"RequestBuilder.buildRequest should return a request with a non-nil User-Agent header")
58-
XCTAssertNotNil(request!.params,
47+
XCTAssertNotNil(request.params,
5948
"RequestBuilder.buildRequest should return a request with a non-nil params attribute")
60-
let actualEvents: Array<Dictionary<String, Any>> = request!.params["events"] as! Array<Dictionary<String, Any>>
49+
let actualEvents: Array<Dictionary<String, Any>> = request.params["events"] as! Array<Dictionary<String, Any>>
6150
XCTAssertEqual(actualEvents.count, events.count,
6251
"RequestBuilder.buildRequest should return a request with an events array containing all " +
6352
"relevant revents")
@@ -68,7 +57,7 @@ class RequestBuilderTests: XCTestCase {
6857
let request = RequestBuilder.buildRequest(events: events)
6958
var jsonData: Data? = nil
7059
do {
71-
jsonData = try JSONSerialization.data(withJSONObject: request!.params)
60+
jsonData = try JSONSerialization.data(withJSONObject: request.params)
7261
} catch { }
7362
XCTAssertNotNil(jsonData, "Request params should serialize to JSON")
7463
}

0 commit comments

Comments
 (0)