Skip to content

Instantly share code, notes, and snippets.

@DaveWoodCom
Created July 4, 2019 20:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DaveWoodCom/b9fb8700b2f99ce7399ccb516e812790 to your computer and use it in GitHub Desktop.
Save DaveWoodCom/b9fb8700b2f99ce7399ccb516e812790 to your computer and use it in GitHub Desktop.
Xcode Test to test the performance of using a `for` loop with a `where` clause vs an `if` statement vs a `guard` statement.
//
// TestProjectTests.swift
// Tests
//
// Based on a question Nick Lockwood asked on Twitter: https://twitter.com/nicklockwood/status/1146508387498303488 .
// And then followed up by GeekAndDad https://twitter.com/GeekAndDad/status/1146630469842116609 .
// These tests were executed on an iMac 5k, against an iOS project running in the XR Simulator.
// My results are included as comments in each test below. I ran the tests 5 times (which itself runs each test 10 times).
// The average of each 10 runs are listed below, as well as the placing 1st/2nd/3rd for each of the 3 styles.
//
// Style 1: for...where
// Style 2: for...if
// Style 3: for...guard
import XCTest
@testable import TestProject
let numberOfElements: Int = 10000
let numberOfIterations: Int = 1000
class TestProjectTests: XCTestCase {
struct SomeObject {
var isWall: Bool = false
}
let someObjects: [SomeObject] = {
var someObjects: [SomeObject] = [SomeObject]()
for i in 0 ..< numberOfElements {
someObjects.append(SomeObject(isWall: i % 4 == 0))
}
return someObjects
}()
override func setUp() {
// Put setup code here. This method is called before the invocation of each test method in the class.
}
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
}
func testABufferPrime_IgnoreTheseResults() {
// This test should always run first and should be ignored
// It's here only to ensure the results of being the first test aren't skewed
// I've seen cases where the first test takes longer (presumably because it couldn't make use of any hardware caching etc)
var count: Int = 0
self.measure {
for _ in 0 ..< numberOfIterations {
for someObject in someObjects {
if someObject.isWall {
count += 1
}
}
}
}
}
func testStyle1() {
// 2.098, 2.263, 2.153, 2.105, 2.084
// 2, 3, 2, 3, 3
var count: Int = 0
self.measure {
for _ in 0 ..< numberOfIterations {
for someObject in someObjects where someObject.isWall {
count += 1
}
}
}
print("\(#function) -> count: \(count)")
}
func testStyle2() {
// 2.089, 2.238, 2.205, 2.080, 2.072
// 1, 1, 3, 1, 1
var count: Int = 0
self.measure {
for _ in 0 ..< numberOfIterations {
for someObject in someObjects {
if someObject.isWall {
count += 1
}
}
}
}
print("\(#function) -> count: \(count)")
}
func testStyle3() {
// 2.107, 2.242, 2.091, 2.092, 2.074
// 3, 2, 1, 2, 2
var count: Int = 0
self.measure {
for _ in 0 ..< numberOfIterations {
for someObject in someObjects {
guard someObject.isWall else { continue }
count += 1
}
}
}
print("\(#function) -> count: \(count)")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment