Periodic reminder to reclaim some hard drive space from unavailable simulators after updating to Xcode 11.7
xcrun simctl delete unavailable
Mark Pospesel (Coding and Other Stuff)
Coding, tech, living abroad, travel, hiking, vintage plastic bricks
Periodic reminder to reclaim some hard drive space from unavailable simulators after updating to Xcode 11.7
xcrun simctl delete unavailable
What recommendations do people have for learning native iOS development (courses, online materials, bootcamps, etc). Paid is fine. (Target audience is junior web/React Native developers.) Thanks in advance!
RCTFatal. I’m guessing this is not a good thing?
And this article helped me create a new project in Xcode 11 that targets iOS 11. I honestly wasn’t sure what to do with the iOS 13 Scene Delegate code.
https://sarunw.com/posts/create-new-ios12-project-in-xcode11/
This article helped me get cocoapods configured for use with a new multi-project workspace.
https://medium.com/@youvalv/cocoapods-for-an-existing-multi-project-workspace-1fb73f46fede
Starting a new project today. Any reason why I should push the client to not support iOS 11? (Not supporting iOS 12 is probably not an option.) Feedback welcome.
Days since I have declared a class as “pubic”: 0
Yesterday I wasted several hours trying to animate both origin and size of a view’s frame. No matter what I tried, the size would always snap to the final value at the start of the animation. Today I said screw it and used CADisplayLink to perform the animation. Finally worked.
Sounds simple, right? But yesterday I messed up this simple operation and was stuck for a couple hours wondering why an API request wasn’t working.
A pattern I follow is to use Swift struct
‘s to represent each network request my app needs. Each struct has only let
properties and conforms to Encodable
so that it can be serialized to JSON and sent to the server by my networking class. Typically this is straightforward and the top-level JSON object is almost always a dictionary.
For example:
struct MyRequest: Encodable { let uid: String let date: Date let bar: Int? }
Thanks to the magic of the compiler, this will encode to a JSON dictionary just fine without any boiler plate code on my side.
Occasionally if the names of the properties don’t match the names of the parameters the API expects (typically because the API is not in my control and follows some naming convention I don’t like – or even no naming convention whatsoever), then I need to declare CodingKeys
to properly map the encoding.
Some times there’s no avoiding it though and I need to implement the encode
function myself. I often need this when the server expects some weird Date format or some business logic is needed for the encoding.
Yesterday I implemented a simple network request that needed to be serialized as an array.
struct CallsRequest: Encodable { let calls: [Call] // Call conforms to Encodable }
The trouble is that this would encode to a Dictionary with one key “calls” whose value is the array. What I needed was to encode to an Array instead.
func encode(to encoder: Encoder) throws { var values = encoder.unkeyedContainer() try values.encode(calls) }
I had never used unkeyedContainer()
before. Previously I’ve always used container(keyedBy:)
, which encodes as a dictionary (hence keyed).
The output of the approach above was an object of type [[Call]]
. That is, it encodes an array of arrays instead of just an array. (Someone else spotted the extra brackets in the JSON output. Thanks Anton!)
It took me a while to realize where the extra level of Array was coming from, but then it dawned on me: the unkeyedContainer()
is an Array, just as the container(keyedBy:)
is a Dictionary.
So what I really needed was something like this:
func encode(to encoder: Encoder) throws { var values = encoder.unkeyedContainer() for call in calls { try values.encode(call) } }
This delivered the expected output of type [Call]
. Problem solved.
Anyway, I hope that someday this might save someone a few hours of frustration.
Where the real JSON encoding happens is via another custom protocol that I didn’t mention. Basically I want objects to be able to convert themselves to Data
so that they could be set as the body to an HTTP PUT/POST/PATCH/DELETE request.
public protocol ParametersBuilder { func data() throws -> Data func dictionary() throws -> [String: Any] }
dictionary()
is for GET requests or for .formUrlEncoded
request bodies. But data()
is used for everything else.
The default implementation of data()
is this:
extension Encodable { public func data() throws -> Data { return try JSONEncoder().encode(self) } }
(which is why CallsRequest conforms to Encodable
and what by default would turn it into a dictionary)
A simpler solution to my problem would have been to provide a custom implementation of data()
on CallsRequest instead of conforming to Encodable
:
struct CallsRequest: ParametersBuilder { let calls: [Call] // Call conforms to Encodable public func data() throws -> Data { return try JSONEncoder().encode(calls) } }
Rob Napier pointed out to me that I could use singleValueContainer
to skip having to loop through the array.
func encode(to encoder: Encoder) throws { var values = encoder.singleValueContainer() try values.encode(calls) }
TL;DR: use @objc
Source: the 5th comment to the 2nd answer to this Stack Overflow question.
Sample code:
@objc public var firstInitial: String { willAccessValue(forKey: "firstInitial") let name = self.name didAccessValue(forKey: "firstInitial") guard let groupName = name, let initial = groupName.first else { return "" } return String(initial).uppercased() }
(and yes I know there are many different ways I could compute the first initial of a string.)