Some examples of Swift code.
Note: type annotations have been added for clarity, but are not required (unless noted).
typealias APIToken = String
for (k, v) in somedict {
...
}
It turns out that Dictionary.keys
does not return an Array
of the keys (it returns an object of type Dictionary.Keys
).
Array(somedict.keys)
To check if a key exists in a dictionary:
if dict.keys.contains(key) {
...
}
Marking a function as deprecated:
@available(*, deprecated)
func myFunc() {}
More: https://stackoverflow.com/a/25406285/7543271
let s: String = "hello"
let d: Data = s.data(using: .utf8)!
let d: Data = Data(bytes: [104, 101, 108, 108, 111, 0]) // "hello"
let s: String = String(data: d, encoding: .utf8)!
Resources:
Resources:
- https://benscheirman.com/2017/06/swift-json/
- https://hackernoon.com/everything-about-codable-in-swift-4-97d0e18a2999
You can't do this (yet):
let s: String = "hello"
let d: Data = try! JSONEncoder().encode(s)
Thread 1: Fatal error: 'try!' expression unexpectedly raised an error: Swift.EncodingError.invalidValue("hello", Swift.EncodingError.Context(codingPath: [], debugDescription: "Top-level String encoded as string JSON fragment.", underlyingError: nil))
The top-level object of the resulting JSON output must be a dictionary or an array (not a string, number, boolean, or nil).
However, this may be supported in the future, see:
struct Movie: Codable {
let id: Int
let title: String
}
Encoding:
let m: Movie = Movie(id: 1, title: "Goonies")
let d: Data = try! JSONEncoder().encode(m)
Decoding from Data
:
let m2: Movie = try! JSONDecoder().decode(Movie.self, from: d)
Decoding from String
:
Convert the String
to Data
first, then decode as above:
let s: String = """
{
"id": 1,
"title": "Goonies"
}
"""
let d3: Data = s.data(using: .utf8)!
let m3: Movie = try! JSONDecoder().decode(Movie.self, from: d3)
As long as the struct
s are all Codable
, they can be nested:
struct Author: Codable {
let name: String
}
struct Book: Codable {
let title: String
let author: Author
}
Encoding:
let b: Book = Book(title: "Not Always So", author: Author(name: "Shunryu Suzuki"))
let d: Data = try! JSONEncoder().encode(b)
Decoding:
let b2: Book = try! JSONDecoder().decode(Book.self, from: d)
struct Movie: Codable {
let title: String
let releaseDate: Date
enum CodingKeys: String, CodingKey {
case title
case releaseDate = "release_date"
}
}
This doesn't work out of the box:
let s: String = """
{
"title": "Groundhog Day",
"release_date": "1993-02-12T22:47:51+0000"
}
"""
let d: Data = s.data(using: .utf8)!
let m: Movie = try! JSONDecoder().decode(Movie.self, from: d)
Thread 1: Fatal error: 'try!' expression unexpectedly raised an error: Swift.DecodingError.typeMismatch(Swift.Double, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "release_date", intValue: nil)], debugDescription: "Expected to decode Double but found a string/data instead.", underlyingError: nil))
You need to set the dateDecodingStrategy
on the JSONDecoder
:
let d: Data = s.data(using: .utf8)!
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
let m: Movie = try! decoder.decode(Movie.self, from: d)
Resources:
We can write a pair of extensions to make this a bit more succinct, for the common case where we simply want an optional returned (and aren't interested in examining the exception).
struct Author: Codable {
let name: String
}
Encoding:
extension Encodable {
public var encoded: Data? {
return try? JSONEncoder().encode(self)
}
}
let a: Author = Author(name: "Mark Twain")
let d: Data = a.encoded!
Decoding:
let a2: Author = d.decoded()!
Note: the type annotation on a2
is required.
Define a CodingKeys
enum which adheres to String, CodingKey
:
struct Author: Codable {
let firstName: String
let age: Int
enum CodingKeys: String, CodingKey {
case firstName = "first_name"
case age
}
}
Encoding:
let a: Author = Author(firstName: "Mark", age: 45)
let d: Data = try! JSONEncoder().encode(a)
Check the result:
let s: String = String(data: d, encoding: .utf8)!
print(s)
{"age":45,"first_name":"Mark"}
Decoding:
let s2: String = """
{
"first_name": "Mark",
"age": 45
}
"""
let d2: Data = s2.data(using: .utf8)!
let a2: Author = try! JSONDecoder().decode(Author.self, from: d2)
struct Movie: Codable {
let title: String
}
movie.json
(make sure this file is added to your unit test target, not your main target):
{
"title": "Groundhog Day"
}
import XCTest
@testable import CodableDemo
class MovieTests: XCTestCase {
func testMovieDecode() {
let b: Bundle = Bundle(for: type(of: self))
let u: URL = b.url(forResource: "movie", withExtension: "json")!
let d: Data = try! Data(contentsOf: u)
let m: Movie = try! JSONDecoder().decode(Movie.self, from: d)
XCTAssertEqual(m.title, "Groundhog Day")
}
}
self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.estimatedRowHeight = UITableViewAutomaticDimension
- Remove any related function definitions (e.g.
heightForRowAtIndexPath
). - Ensure your cells have a continuous chain of vertical constraints from top to bottom.
var playableCell: UITableViewCell & Playable = ...
super.updateConstraints
should be called last. Use defer:
public override func updateConstraints() {
defer {
super.updateConstraints()
}
...
}
WWDC 2018 #220 is a great resource for building an intuition around the performance impact of calling updateConstraints
. TL;DR: keep this method as optimized as possible.
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?
) -> Bool {
let window = UIWindow(frame: UIScreen.main.bounds)
window.makeKeyAndVisible()
window.rootViewController = UIViewController()
self.window = window
return true
}
}
Also remember to empty out the "Main Interface" field under the "General" tab of your target's settings.
without casting:
switch item {
case is Int:
...
case is Double:
...
with casting:
switch item {
case let i as Int:
...
case let d as Double:
...
Sometimes you need to switch on the cases of two enums:
enum Content {
case article(URL)
case video(URL)
}
let a: Content = .article(URL(string: "http://google.com")!)
let b: Content = .video(URL(string: "http://yahoo.com")!)
switch (a, b) {
case (.article(let url1), .article(let url2)):
...
case (.video(let url1), .video(let url2)):
...
default:
...
}
extension Observable where E == Int {
public func foo() -> Observable<Int> {
...
}
}
import struct FloSportsCore.Event
Turns out you can't implement Hashable
on a tuple. https://stackoverflow.com/a/24152255/7543271