Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
NSHipster New Year's 2016

Greetings and salutations, NSHipsters!

As the year winds down, it's a tradition here at NSHipster to ask you, dear readers, to offer up your favorite tricks and tips from the past year as gifts to your fellow hipsters. With iOS 9, El Capitan, brand new watch- and tvOS's, and the open-sourcing of some minor Apple-related tech, there's bound to be lots to share.

Submit your favorite piece of Swift or @objc trivia, helpful hints, unexpected discoveries, useful workarounds, useless fascinations, or anything else you found cool this year. Just comment below!

If you need inspiration, try the list from last year, or from the year before, or from the year before that.

새해 복 많이 받으세요! 🎆

@mhuusko5
Copy link

mhuusko5 commented Dec 25, 2015

Using Swift's _ObjectiveCBridgeable (implicit castability between types) to create a generic protocol for Obj-C compatible objects that wrap pure Swift structs (keeping Swift framework API clean, but Obj-C compatible for as long as desired), e.g.:

public protocol BackedObjectType: AnyObject {
    typealias Backing

    var backingObject: Backing { get }

    init(_ backingObject: Backing)
}

public protocol ObjectBackable: _ObjectiveCBridgeable {
    typealias Backed: BackedObjectType
}

public extension ObjectBackable where Backed.Backing == Self {
    static func _isBridgedToObjectiveC() -> Bool { return true }

    static func _getObjectiveCType() -> Any.Type { return Backed.self }

    func _bridgeToObjectiveC() -> Backed { return Backed(self) }

    static func _forceBridgeFromObjectiveC(source: Backed, inout result: Self?) { result = source.backingObject }

    static func _conditionallyBridgeFromObjectiveC(source: Backed, inout result: Self?) -> Bool {
        _forceBridgeFromObjectiveC(source, result: &result)
        return true
    }

    func toBridgedObject() -> Backed { return _bridgeToObjectiveC() }
}

/////     /////     /////     /////     /////     /////     /////     /////     /////     /////     /////     /////     /////     /////     /////     /////     /////

public struct SomeModel {
    public let ID: Int
    public let name: String
    public let category: String
}

/////     /////     /////     /////     /////     /////     /////     /////     /////     /////     /////     /////     /////     /////     /////     /////     /////

extension SomeModel: ObjectBackable { public typealias Backed = M5SomeModel }

@objc public final class M5SomeModel: NSObject, BackedObjectType {
    public let backingObject: SomeModel
    public init(_ backingObject: SomeModel) { self.backingObject = backingObject }

    public var ID: Int { return backingObject.ID }
    public var name: String { return backingObject.name }
    public var category: String { return backingObject.category }
}

/////     /////     /////     /////     /////     /////     /////     /////     /////     /////     /////     /////     /////     /////     /////     /////     /////

let model = SomeModel(ID: 2, name: "awesome", category: "music")

let objcCompatibleModel = model as M5SomeModel

let originalModel = objcCompatibleModel as SomeModel

@tfrank64
Copy link

tfrank64 commented Dec 28, 2015

The addition of the where clause has made my code simple and compact while remaining readable. In addition, it has a broad application in Swift, so that it can be applied in nearly any kind of control-flow statement, such as for loop, while loop, if, guard, switch, and even in extension declarations. One simple way I like to use it is in my prepareForSegue method:

if let segueID = segue.identifier where segueID == "mySegue" {
    ...
}

The combo of unwrapping and performing a condition check is most commonly where I use the where clause. The where clause is not going to change your life, but it should be an easy and useful addition to your Swift skills.

@jcavar
Copy link

jcavar commented Dec 30, 2015

Additional type safety with phantom types:

struct Kilometer {}
struct Meter {}

struct DistanceT<T> {
    private let value: Int

    init(value: Int) {
        self.value = value
    }
}

func +<T>(left: DistanceT<T>, right: DistanceT<T>) -> DistanceT<T> {
    return DistanceT(value: left.value + right.value)
}

extension Int {
    var km: DistanceT<Kilometer> {
        return DistanceT<Kilometer>(value: self)
    }
    var m: DistanceT<Meter> {
        return DistanceT<Meter>(value: self)
    }
}


let distanceKilometers = 5.km
let distanceMeters = 15.m
let newDistance = distanceKilometers + distanceKilometers // Ok
let newDistance = distanceKilometers + distanceMeters // Compiler error

@orta
Copy link

orta commented Jan 2, 2016

@joemasilotti
Copy link

joemasilotti commented Jan 7, 2016

How to tell if your app is running under UI Tests:

UI Tests:

class UITests: TestCase {
    let app = XCUIApplication()

    override func setUp() {
        super.setUp()
        app.launchArguments = ["UI-TESTING"]
        app.launch()
    }
}

App Code:

func UITesting() -> Bool {
    return NSProcessInfo.processInfo().arguments.contains("UI-TESTING")
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment