Apple’s use of Swift in iOS 12
blog.timac.org
blog.timac.org
The only reason I suspect that Apple is not all over Swift is that many of their programmers are the type of coders who like falling back to C when they feel they need a performance boost. Perhaps they like the message-like nature of ObjC. Dunno. I can say that I've been able to get apps to 0 fixable crashes with Swift (some crashes are system level), not something I've ever done with ObjC, let alone Java for Android.
Having worked on a large Obj-C codebase that began adopting Swift, there are definitely some headaches involved in Obj-C/Swift interop, and you often aren't getting many benefits of Swift unless your new code has few to no dependencies on / is not depended on by Obj-C code, unless you can refactor it into Swift.
Given how quickly it seems they've been forced to ship, I can understand not wanting to deal with these issues, or not having the time to address them.
- It was easier to hire developers
- Code was less prone to null pointer exceptions
- There were fewer assumptions when deserializing JSON into a struct/object
Not saying that it's an unsolvable problem elsewhere, it's just an anecdotal benefit we got
It's weird using Swift and realizing how much of that trouble we went through is avoided just by not using a GC'd language
Reference counting is listed as a strategy to achieve garbage collection. Broadly speaking, garbage collection is the process of automatically managing the lifecycles of objects in memory, which reference counting certainly achieves.
```
struct Node {
var next: Node?
var prev: Node?
}var a = Node(next: nil, prev: nil)
let b = Node(next: nil, prev: a)
a.next = b
```
These two objects will persist in memory for the entire life of the app even when all reference to a and b are gone, except for their references to one another.
Question for anyone who knows: what percentage of Apple's application-software programmers double as system-software/kernel programmers? Because I expect that'd color their preferences for a daily-driver language quite a bit.
I've developed since for version 1, small utilities, and even for those projects, it was not enough.
Version 4 and it's my favorite language to develop for.
More likely the language just matured. I'm glad they were not afraid to iterate as it is hard to get everything right on the first try and being stuck with a suboptimal design for the next 20 years would have been much worse.
This is, in many ways, the diametric opposite of what this thread is discussing: pushing out nominally "stable" versions to the outside world, breaking things, but not committing internally.
Apple prides itself on "not shipping beta products", which kind of BS.
In Swift, this is currently not stable, meaning it changes with each version. The result is that you can't use a library compiled with version X of Swift with version Y of Swift. From version 5 onward the ABI will be compatible between version 5 and versions >5.
https://www.reddit.com/r/swift/comments/8zb9y1/state_of_swif...
For that, I'm exploring with rust now, but certainly is far harder than use swift.
I also look at nim, yet I think is too inmature for use in ios/android?
Even if a keep rust I think nim cover a nice spot to add to the toolbet.
Swift is a great language to work in.
By doing optional chaining you can do something like: if let name = result.person?.firstName { ... } which only evaluates firstName if person is not nil, and then stores the result in name which is immutable.
It's easier to avoid mutable code in Swift than in many other languages. For this reason I would love to start working with Swift on the backend at some point in the future.
I like extensions, being able to extend any class I want by just typing it into any file I want. This helps with iterative development and trying something out.
Speaking of iteratively, if I want to try something quick, I can also drop down to a shell and start the Swift REPL to experiment.
I like how built-in functions like zip and mapValues are available, so it in some ways has a Pythonic feel. I like the syntax of building strings by just taking a variable name and going let s = "Hi there \(name)!".
There are lots of other things I enjoy, such as subscripts (see why here: https://docs.swift.org/swift-book/LanguageGuide/Subscripts.h...) and
Some things I would like to see improved is Xcode itself and also Swift's capabilities in the backend.
I've been waiting impatiently for a better Swift backend ecosystem, because I'd love to use it for web development as well.
- rich enums - (https://appventure.me/2015/10/17/advanced-practical-enum-exa...) Much of my code is now encapsulated in the enum, where it logically belongs, instead of distributed throughout some class that consumes the enum.
- highly expressive pattern matching - (https://appventure.me/2015/08/20/swift-pattern-matching-in-d...) Swift's pattern matching is especially powerful with a switch statement. I frequently bundle multiple values into a tuple and switch across them, which allows me to flatten many if-else pyramids, and makes control flow more obvious up front.
- Optional - (https://developer.apple.com/documentation/swift/optional)
- Protocol extensions - (https://docs.swift.org/swift-book/LanguageGuide/Extensions.h...) Other languages use things like abstract classes or traits to implement this behavior, but I find protocols to be much more composable.
- The standard library - Swift's standard library is really well thought out. Many standard types have been built on top of highly reusable (and easy to reason about) types or interfaces that provide enormous utility when I adopt them in my custom types. Examples of this are: Codable (https://developer.apple.com/documentation/foundation/archive...), Equatable and Hashable (https://developer.apple.com/documentation/swift/adopting_com...)
There's more than that, and Swift is definitely not without it's shortcomings, but those features have fundamentally changed how I reason about code. I frequently find myself wishing I could reach for similar tools in other languages.
I know Apple was heavily involved in the Dylan language several years ago. Does anyone know if Swift was influenced by Dylan ?
A shared dyld cache would be a cache of metadata used for linking, but not sure if that is for link-time or runtime.
Obviously, it's not Swift's fault for that, but even if people at Apple make rookie mistakes such as using force unwrap operator, it tells something about the language.
Actually I was wondering with Swift had a lot of these things I don't see much in other languages. Optionals for example. Is it because it us focused on coding highly responsive UIs where different states might not yet be available?
But most new languages has some variant of this stuff: kotlin, scala, rust.
I program a lot in Julia which is a script language and it does not have allow you to use null freely either. May seem odd for a language that does not type check at compile time. But it actually makes sense.
It's still often suggested by Xcode if you use an optional which has not been unwrapped in any way. "Click here to make error go away" adds an !.
--
[0] Unless you could invert the order of the unarchiving...not sure what difficulties that would cause.
C-family languages let you take off your whole leg with the slightest mistake.
In defence of Swift, it could still be that they spent less time bug-hunting than when they were developing in Objective-C, to reach the same, or inferior, level of program correctness.
Also, we're comparing a new product to a mature one. Were the original Objective-C programs stable in their first release?
Apple could have continued using the existing software, rather than just throw away stable code for the sake of new devs to use a new language.
Mandatory link to Spolsky's blog post on exactly this:
https://www.joelonsoftware.com/2000/04/06/things-you-should-...
Of course, mixing with Objective-C may actually be the cause of issues or crashes? Who knows.
In fact, I would argue that this new trend of defensive programming in Swift will make software worse in the long run. We had a tradition of sending crash reports back to developers. If everyone now starts their methods with `guard let param = param else { return }`, software will silently fail on end user devices, and everything will look fine in Crashlytics/App Store Connect.
I'm not saying that this is what your apps are doing. But I know that Apple bragged about their record low in crash numbers at a time when I ran into different glitches across all of their apps every single day. It's a flawed metric.
Also, take into account that in Objective-C you can send any message to a nil pointer, and the result will be nil or 0 (for scalar types), as defined by the language standard.
I generally find it useful to have the concept of Optional, making me think about "could this thing be missing?" explicitly. But I've started to wonder if it is, rather than "preventing an entire class of bugs", actually just making them pop up elsewhere when Optional values start brushing up against that top level of user-visible stuff.
Maybe we (I) just need to get better at thinking about missing data conditions at the product design stage, or more robust defaults.
Perhaps you are under-using sum types - or enums with associated values as they are called in Swift. Difficult to get into details in this format, but for example, instead of:
`enum State { case connected(Connection, SomeOtherStateRelatedToConnected) case disconnected }
let state: State `
You have: ` var connection: Connection? var someOtherState: SomeOtherStateRelatedToConnected? `
I'd agree if Swift was a general-purpose C++ replacement, but most developers use Swift to write Cocoa apps. viewController.navigationController is optional, view.superview is optional, label.text is optional; all of Apple's frameworks are built on mutable state where almost everything can be or become nil.
(We can make sure that most variables and parameters aren't optional, but that only pushes the problem to other lines of code.)
If we know that we've loaded a view controller from a storyboard, is `self.storyboard!.foo` really a code smell? What else should we do? The type system doesn't let us express what we know/assume about the situation, unless we completely sidestep Apple's controller infrastructure and write our own thing.
> Also, take into account that in Objective-C you can send any message to a nil pointer, and the result will be nil or 0 (for scalar types), as defined by the language standard.
Right, I am not saying that Objective-C handled this any better. But it boggles my mind that we have Swift's complicated type system now, and use it to rebuild an implicit source of errors from Objective-C.
All the existing Apple frameworks where originally designed for Objective-C, and if redesigned with Swifts type system they could have a much safer API. But what are you suggesting Apple should do? Throwing thousands of man years of their own and third party developers code away, and ask everyone to start from a clean state? I prefer the current approach where, while the Swift language and tooling is maturing, Swift acts as an incremental improvement over Objective-C.
I should also add that if you avoid putting too much of your code in your views (networking, data storage ...) then you can put those components in embedded frameworks that can have a nice safe Swift API.
Apple could have spent less time on their new programming language if they hadn't insisted on reverting every single design decision in Objective-C: the way mutability and constness are handled, NSObject as a root class, naming conventions, the string class, creating their own package manager, etc. There's so much pointless bridging going on.
That would have given Apple plenty of resources to iterate on their current UI frameworks. If the IB/storyboard infrastructure leads to nil-heavy and stringly-typed code, why not push a first-party UI DSL? Why do we even need a third-party platform like Crashlytics to debug errors? Why is it so hard to write UI tests and have them run on a CI? Has IB_DESIGNABLE started working reliably at some point? Why is basic stuff like this not a blocker? [1]
And yes, at some point I think UIKit and AppKit should be scrapped in favor of a new framework (with a slow migration path, not a clean cut). I was hoping for UXKit to be just that, but instead we got the monstrosity that is Marzipan. Apple's focus is on the language, when it should be on the frameworks.
[1] https://bugs.swift.org/plugins/servlet/mobile#issue/SR-6795
But every one of these is arguably a good decision. Swift.String has a significantly better interface. immutable types are a huge win. It doesn't make sense to have a root class when you have non-class value types. You have to change the naming conventions if you change the calling syntax, which was a swift goal.
You also can't take LLVM gurus working on a new language and re-task them to take on UI framework feature adds without a lot of friction.
(BTW, my understanding was that NSObject isn't the only root)
Foo was rewritten in Swift, and bar was super buggy. Why would you blame that on Swift?
Turns out one of these bugs even has its own blog post: https://medium.com/@julioromano/working-around-an-infamous-m...
However if you adopt different patterns with Swift you can exclude a lot of optionals, for example if you give every View a State enum with associated values you can avoid quite a lot of optionals:
class PersonView: UIView {
enum State {
case empty
case loading(personId: String)
case loaded(person: Person)
}
var state: State = .empty {
didSet {
switch state {
/* handle all different states */
}
}
}
}
Every time you switch state you need to give the right associated value and every time you are in this state this value is guaranteed to be there where before you would have an optional personId and an optional person.And it's applicable almost everywhere. I barely use optionals anymore unless I really can't replace them with an emum.
Have you tried
Crashlytics.sharedInstance().recordError(error)
I use it to log errors on API calls in my projects. It comes in handy when I'm using third-party services and they decide to break something on their end.Swift is not defensive, Swift can be defensive, but it can not if you don't want to.
It's much more "offensive" than Objective-C, for example.
Just a "!" and it's the same as Null Pointer Exception == Fatal Error.
This seems to contrast MS when they released .NET but shied from using it in their own systems (though I might be wrong)
The performance difference between the garbage collected runtime and its C predecessor was too much and initial attempts at the rewrite in C# with Longhorn were a major fail.
Then there was Longhorn, which failed more due to internal politics than due to technical issues, as Midori later has proven just to be killed by management, as decribed by Joe Duffy postmortem reports.
WinRT/UAP/UWP are built on top of improved COM, and .NET has a native personality for them, using AOT compiler for WinRT/UAP (MDIL) and UWP (.NET Native).
Most of the new UWP stuff is written in .NET Native, with C++ taking care of the UWP runtime infrastructure, and the DirectX composition engine (Visual Layer).
The majority of Windows UI team UWP and FluentUI demos are usually done in .NET Native.
Silverlight was more of a platform than an "internal product" and it was based on .NET so it was only natural (it doesn't seem to have taken off though)
And yes .NET makes COM usable (well it is usable using MS libraries in C/C++, otherwise, forget about it :) )
IDispatch and variants were/are an abomination.
The problem that we have is that we have so much infrastructure around C++ that it is expensive to switch. Even if you get faster compile times or theoretically less memory management bugs, you may lose the productivity in other ways if the rest of your tooling isn’t there.
With C# you definitely pay a small cost in memory consumption and a decent cost in binary size vs. C++ though, which still matters.
On a side note, iOS 12 was great but seems riddled with memory leaks that eventually require a reboot every few days.
Are you sure you're not talking about storage space? I don't know what memory diagnostic app you're talking about.
Sure it's not 'the memory diagnostic app' that's wrong?
Don’t forget to update your anti-virus too!
How's that so? An app doesn't have to leak OS memory, just leak its own memory.
It's unsafe for the kernel to swap the memory out, because paging doesn't (usually) work while running kernel code.
It might be called "non-pageable", "pinned", "non-swappable", etc. Out of those, I'd prefer "non-pageable", because it's the most descriptive term for it.
Non-standard terminology is not great for communication.
Really ? Because it's literally called that in macOS Activity Monitor app, the term is also used in Apple's kernel documentation and API's (e.g. in the `mem_and_io_snapshot` struct defined in 'debug.h' in Kernel.framework). It's also mentioned in the Kernel Programming Guide.
Never did macOS drivers, just bare metal, Windows and Linux so far, macOS is not very big in our niche. Weird that Apple's terminology is so different.
Typing this on a Macbook Pro, and I can see that Activity Monitor does mention "wired" memory.
For what OS? Consider https://wiki.freebsd.org/Memory
Wired
- Non-pageable memory: cannot be freed until explicitly released by the owner
- Userland memory can be wired by mlock(2) (subject to system and per-user limits)
- Kernel memory allocators return wired memory
- Contents of the ARC and the buffer cache are wired
- Some memory is permanently wired and is never freed (e.g., the kernel file itself)
OSX is derived from BSD.Check my other reply above. Did some FreeBSD work ~15 years ago, but I guess I'd already forgotten.
Love, - guy who writes software and knows that all software is terrible
It really amazes me how people are always forming ideological groups - C vitamin is the best cure for everything. C vitamin is useless, just forget it. iOS has memory leaks. No, you are holding it wrong, iOS 12 is good.
And here at least we are a techy bunch, but outside the tech circle, how people treat software is just astonishing. Like the guy who made photographs sitting on the passenger seat, because his Tesla is a full autonomous car and it is perfectly capable of driving by itself.
What I’ve noticed is that everything is faster. Until it suddenly isn’t. And then swiping between home screen pages takes approximately one full second and only shows one intermediate animation frame. In other words, it suddenly is unusable. Background app chewing up resources? No idea. I just know it didn’t do it in iOS 11.
Oh, and this was throughout the beta. It’s been decreasing as time goes on though.
>Are they using it in the top ten (mail, web, cal, clock, etc.)?
No.
>How much of Swift compared to ObjC code?
Much less.
It makes sense too. You don't rewrite perfectly good programs in a new language just for the fun of it.
The Holy Grail of software engineering
It also allowed us to get more people involved in development. People new to apple development found Objective-C to be a bigger barrier. Odd syntax and a bit old fashion.
Mind you I quite liked Objective-C. But it seems a bit pointless when you got Swift.