And just today I was contemplating writing my first native iOS and macOS app... I was looking at the options and decided to go native with Swift. I have never written Objective-C app and never used x-code for dev. But I have ~10 years of dev experience, mostly Java and Python on the backend and front end dev exp mostly with Angular. Some Android, and a little from <input_random_tech_here> because I like to experiment.
So, my question is. How hard and enjoyable is for someone like me to write not very complex native iOS/macOS app in Swift starting from scratch? Best resource to start with?
Hardest part isn't the language. Swift is among the best languages you can get today. IOS sdk, on the other hand, has become a bit of a mess, due largely to the pace at which the field is moving ( although not as bad as android).
If you know, say Agda, Idris is not hard. The point is the concepts in Idris are hard, not the language. People learning haskell as first language in universities have more difficulty learning OO language than we have as we already know many OO languages.
The Android framework is honestly a huge pain to develop with. I switched over to iOS development a year ago and am much happier. It feels almost impossible to get Activity/Fragment life cycles correct for simple things. And anything View related has to pass around a God Context object.
For ios : look at the number of various apis you can use to do widget positionning and animations : calayer, uiview spring n struts, constraints, physic based, and yet none compose well with each other.
IOS also doesn't have any good tech for offline storage ( core data should be burried once and for all) and swift relies on compile-time codegen hack to provide easy struct serialization, because techs like nscoding relied on obj-c runtime facilities and the language itself doesn't provide enough metaprogramming facilities to compensate.
Also, patterns like KVO are still found from time to time as a last resort in frameworks, while being famously unsafe and still rely on the obj-c runtime.
For android basically everything should be rewritten from scratch. Last time i managed a team of android developpers, we basically came to the conclusion that doing regular mvc while supporting a good market share meant recoding our own controller base classes and screen transitionning apis.
>> For ios : look at the number of various apis you can use to do widget positionning and animations : calayer, uiview spring n struts, constraints, physic based, and yet none compose well with each other. IOS also doesn't have any good tech for offline storage ( core data should be burried once and for all)
I disagree with most of this. Laying out views was a mess for a while but auto layout is easy to get right once you understand the fundamentals (especially when used in storyboards). Springs and struts is old pre-autolayout tech which shouldn't be used. CALayer is the lower level object that UIView is based on. Not sure what the complaint is here (they're mostly unrelated to autolayout/springs and struts).
As for CoreData it's a pretty simple way to manage your data. When originally introduced to iOS it was a mess but I've used it extensively in the last few years, first through a higher level framework (MagicRecord I think?) and now directly and it providing you exercise some care around threading it performs very well, especially for something simple like offline data storage.
Ever tried to have 60fps on a tableview with constraint-based layout cells ? CALayer is definitely not legacy, it's often the only way to get smooth animation. Spring n struts is also sometimes the best way to get fast position for smooth scrolling.
Ever had to deal with Core Data migration on an app that needs to evolve throughout the year ? Migration is a mess, and so is concurrency.
My personal conclusion after having used Core Data on a pro application for 4 years, is that most of the time i really don't need a database and so i'm back to file-based backups for my app's data. Works well, no magic, and no performance or threading issue.
We ran some casual benchmarks on this at work once, and it's important to note that the performance of AutoLayout dramatically improves based on the degree of nesting you employ.
If you have sixteen views on a cell and their locations all depend upon each other, it's going to take a long time to solve those constraints. But if you can break up the cell, say into four subviews with four elements inside them, it's likely to be faster (no guarantees, though)
Yup, it's easiest if you understand what the solver is doing and help point it towards solutions/find them trivially.
Unfortunately, i had to write my own constraint system and practice with it a lot to use AutoLayout with high performance where i was confident i was not introducing significant re-layout performance problems.
I came to the same conclusion WRT core data. I'm caching data myself to files. I would use SQLite directly if I need a real data store before I would use code data again
How in the world did you managed to use storyboard? I hate using it for moderate-complex UI apps. This guy say it better than me on why I hate storyboard (especially the first reason):
I use it in combination with programmatic UI for more complex things but find it's so much easier and faster when doing auto layout to just use storyboards.
The real reason for which i stopped using them is that it doesn't work well with git. As soon as you've got more than one people in the team, it's over.
It is actually a solvable problem if you're willing to dig into the details of the file changes. It isn't pleasant, but welcome to life. Team members can make conflicting changes as long as someone is willing to dig through the mud to make them all agree with each other. I've been doing it personally for a long time, it isn't my favorite part of the job but it does enable significant parallel productivity.
So you start some sequence (like a new UIViewController) and interact with it via callback events instead of having a single (blocking) thread of execution that waits for the view controller call to return like a function. This makes it virtually impossible to deterministically model flow control. Note that since Android copied many metaphors from iOS, it also inherited these complexities in things like its Activity class.
I agree that Core Data probably needs to go away (at least its iCloud integration) and be replaced by Firebase or PouchDB etc.
KVO was a great missed opportunity because it's not clear who is watching a value. I think the pattern itself has merit from a functional programming perspective (after all this is how Excel works).
I generally avoid native mobile development now for these reasons among many, not to mention cross-platform issues. We likely need web metaphors running above native code, writing plugs where necessary (like Cordova or React Native). These are generally quite painful to use though, so I don't see many solutions materializing for at least several more years.
>So you start some sequence (like a new UIViewController) and interact with it via callback events instead of having a single (blocking) thread of execution that waits for the view controller call to return like a function. This makes it virtually impossible to deterministically model flow control.
Why on earth would you have a single blocking thread on a UI app?
What I was trying to say is that in the olden days of say the 80s, Mac OS used cooperative threads and you just wrote a main loop that was completely self-contained. We made OS calls from there, the OS didn't call us with events like it does today (at least most of the time). So programs were much simpler to debug because we didn't have callback or goto hell.
The tradeoff was that it took pages of boilerplate to make even the simplest app, and Apple got made fun of incessantly for it. So they largely fixed that with OS X's message passing metaphors, but unfortunately due to bloat and a lot of other reasons, the boilerplate issue came back, and now we're also stuck with untraceable program flow.
To answer the original question - I have worked on both blocking and nonblocking code, and unfortunately nonblocking code doesn't scale. It eventually becomes too complex to follow the flow. It's like comparing a coroutine to a state machine. My personal feeling is that we're in a kind of nonblocking bubble right now and that the callback style that pretty much all frameworks use today is not going to be the way it's done in the future. I don't know what will replace it, but it will likely be something more like Redux/Elm/Clojure and declarative GUI syntax like how the web used to work.
It also doesn't help that these APIs are rapidly changing, in ways ranging from minor rearrangements that the XCode auto-upgrader can mostly handle, to real porting hassles. I've been working on a project that was started in early 2016, so it was originally in Swift 2, the then-current version. A ton of things changed for Swift 3, which came out 6 months later, in late 2016. And a bunch of things are changing again with Swift 4 (although not as many as in the 2->3 upgrade). I haven't yet looked into Swift 5, but presumably that brings yet more API changes.
A lot of time is spent just on this treadmill of porting previously working things to modified APIs. To make it worse, you have to manage a 4-way compatibility matrix between Swift versions, XCode versions, iOS versions, and macOS versions, where only very specific combinations work.
AFAIK Swift 3 was supposed to be the last version to introduce breaking changes. Have they changed that policy? I know that the last Swift update I did was very manageable compared to in the past (where I'd easily lose a day or two).
This project's still on Swift 3, so I don't have first-hand experience upgrading to Swift 4. It looks like there are breaking changes though, albeit not nearly as many as 3 had.
The most notable one looks like in the String API [1]. There are a few other minor ones that most projects won't hit, like in the dictionary/set API [2]. A few of these are also slightly more breaking than it initially seems because they've added temporary compatibility workarounds marked as deprecated in Swift 4 to avoid breaking as much working Swift 3 code, but these will go away for Swift 5, so you do still have to port anyway (just not immediately).
I don't see why keyed archiver wouldn't work with swift. I've implemented identical systems in C++ with no dynamic features. Or you can just use JSON serialization for offline storage. I pretty much never use core data. Don't get why people use it so much. On iOS you are a single user of your data so you can easly rely on a combination of plain files for storage. I've seen how Java devs go crazy using core data to just store a few hundred bytes of data. I think people overcomplicate storage 90% of the time.
Keyed archiver doesn't work with structs, and it also probably doesn't work whenevr you start nesting classes. It relies on introspection and dynamic typing for that, which can't work right now with swift.
It's one reason they had to rely on compile-time codegen to implement the swift4 equivalent.
For me it feels like the messaging is pretty clear: use AutoLayout. Springs and struts aren't used anymore, constraints are just a part of how AutoLayout works, and I'm not even sure what you mean by physic based.
I found myself wasting months to do something that should have been handled better in iOS.
- APIs return non-descriptive error codes like -16405. Some of them aren't documented. And even the ones that are are not found clearly. Different codes are documented in different files. If you don't know where to look, you won't find it. Java-style descriptive error names like InvalidFrameRateException are sorely missing. iOS should either adopt exceptions or at least string error codes like INVALID_FRAME_RATE, not -16405.
Sometimes, there's no error code at all. I'm trying to record a video, using a AVCaptureMovieFileOutput, which is supposed to save to a file, and it doesn't. There's no error code, no exception, no log message telling me what went wrong and how to fix it. I spent a day or two trying various possibilities but nothing worked.
- Common abstractions like a photo gallery class aren't missing. It took me a month to write my own, because there are a lot of cases to deal with: swiping left and right, pinching to zoom, double-tapping to zoom, keeping the photo centered while zooming, taking care not to zoom the whitespace, keeping the photo gallery in sync with the Photos app (the user might delete a photo either in your app or in the Photos app, and you need to sync in both directions), and so on. Even now my gallery class doesn't support swipe down to close, which the Photos app supports, as I was told yesterday. That's what happens when you make people reimplement things — you'll get an inconsistent UX.
Forget a photo gallery class. Even a zoomable photo view is missing. It took me days of messing with UIScrollView to figure this out, until I found the ray wenderlich tutorial.
- Some APIs come in both sync and async versions, while others, like permissions, come only in an async version, though a sync version would be easier. Even the async APIs are inconsistent -- some invoke your callback on the main thread (UIKit APIs), some invoke it on the same thread you invoked it on, and some in a random thread (AVCapture). I filed a radar asking for consistency (maybe all async APIs can take a queue to invoke the callback on) but Apple closed it as WontFix.
Unfortunately, Swift doesn't have async/await, so dealing with the async APIs is a pain, and for some reason, this is not even a priority in Swift 5. It's being put off for years.
- Permissions are a pain to deal with, especially the common case that your app can't run without some permissions, like Camera and Photos for a camera app. I had to deal with the following cases:
+ You should take care to request a permission only after the previous one has been approved or denied by the user. Otherwise, you'll get a prompt for Camera, and before you respond, it disappears and is replaced by a prompt for Photos. And before you can respond, it disappears and is replaced by Location. When you respond to it, the Camera prompt re-appears, but again disappears and is replaced by Photos. This is a bad UX, caused by iOS not queueing multiple permission requests internally and asking the user for one only after the previous request was responded to.
+ You should ask for location before camera, because a GPS fix can take time.
+ You should take care to obtain permission before accessing the camera, otherwise the camera will vend frames consisting of black pixels, which you might accidentally save to the Photos app.
+ iOS distinguishes between a permission being denied (by the user) and restricted (by an admin or parent). My app would crash in the latter case, because the camera device is not found. But not in the former, because the camera exists but vends black frames.
+ If the user changes permissions of your app while it's running, Apple says that iOS will kill your app and restart it so that you don't have to deal with permission changing dynamically. Except when it doesn't, which goes back to the denied vs restricted case above.
In summary, you waste months of your time working around insufficiently-documented iOS issues, or debugging things, or reimplementing common things in every app.
I conclude that iOS is a poorly-designed platform from the developer point of view. Maybe other platforms are worse, I don't know, but iOS certainly is far from what it could have been. Ideally, you should implement only what makes your app unique.
I'm surprised no one has mentioned this but I'd say the #1 resource for learning the practical 'how do I get X thing done in a couple of hours' are tutorials on https://www.raywenderlich.com/ without a doubt.
It has tutorials for every basic question imaginable in a very easy to follow manner.
It'll definitely take some time, as for being enjoyable - I don't get a kick out of learning an entire new set of libraries and idioms for achieving the same thing I can do in another toolset, but if you do, then great :)
One last thing - the amount of information for macOS is about 1% compared to iOS, so I'd definitely go the iOS route.
> One last thing - the amount of information for macOS is about 1% compared to iOS, so I'd definitely go the iOS route.
I thought that too, but it’s not accurate at all, from recent experience. There is a lot of hidden treasure for macOS, but it is buried under layers of bad Google results because somehow “NSViewController” makes Google shows me results for “UIAppDelegate” and “UIView”—makes sense. A lot of information is out there, on SO, Apple developer forums and mailing lists.
Depending on complexity of your app and the level of polish, it might take a while.
I mean, you can make an app in a day if you follow a tutorial, but if you want to enjoy the language and what you're doing, then you'll have to put in the effort.
Objective-C can probably be avoided, but will help a lot in some cases - especially when interfacing with libraries written in ObjC or C++. So you might want to learn them in parallel, or at least spend a bit of time understanding the semantics of the language, memory management, concurrency, etc.
Oh and native iOS is different from native macOS, some APIs are not compatible, but you can reuse quite a bit of utility-level functions related to your app (since it's the same language).
I enjoyed learning ObjC and Swift and writing apps for iOS, the only issue I have with this platform is that it's too crowded for (new) solo devs.
If you don't care about that as much, then by all means go ahead, you will love it.
Regarding iOS and macOS kits, all of the documentation is in Objective-C. The libraries' Obj-C is imported and usable with Swift-only code, but the Swift documentation lazily links you to examples in the Obj-C docs. You have to perform trial-and-error by manually converting the Obj-C examples into the equivalent Swift (which often entails renamed classes, methods, types, etc.).
If your projects typically do a lot of string parsing, get ready for a world of hell. Swift 4 didn't improve upon the very basic ability to extract a substring from the middle of a string. It takes 3-4 lines of code, with throwaway explicitly defined variables, to do the equivalent of a str.substr(start, end|length). It boggles the mind that you can't do a str.utf8.substr(3, 5) in Swift.
I only remember a very early review of string operation speeds that was pretty bad at times indeed. But that was about Swift 1 and the string implementation has been changed a few times. Do you have any recent source?
Personal experience making the same command line util in python and swift 3 that was parsing code with the same C library (sourcekit) and then doing a bunch of string manipulation after that.
Optimized swift 3 & python were the same speed, with %80 of the time being spent in the C library. I would expect swift would at least be 2x faster in that %20 portion that wasn't sourcekit library.
I think strings in Swift are primarily meant to be very correct above being fast or easy to use. It's more strict than both Python 2 and 3. Handling of languages that use really complex character compositions springs to mind.
You'll get up to speed in no time. Start with WWDC videos [1] in an area you're interested in. Then play around with some of Apple's sample code [2] and modify an app to your liking.
After you're a little more advanced, check out the resources at objc.io [3].
I did this a couple of years ago on a completely fresh MVP for a friend.
Worked fine, my background was in trading systems using C#, Python, and C++. I'd also done a lot of Android Java for another app MVP, so interesting to compare how iOS and Android do things.
I think most people who've done a few languages are not going to find a lot of problems with Swift. There's a lot of nice sugar in there to keep things neat.
Your main issue if you haven't done iOS before is learning iOS. It's a bit weird, you can tell some libs haven't been upgraded while others have. The old libs need a bridge header and have weird relics from Obj-C. Also the whole constraints layout system might take some getting used to, but I did manage to build some pretty complex components with it. It didn't seem to map well onto the Android layout engine, but I'm not that experienced with the layout engines.
Yeah, up-to-date was assumed in my post. I don`t want a post about Objective-C from 2012.
I don`t know if it is against the guidelines to post this kind of links but I found this https://designcode.io/ (I have 0 affiliations with the product) that looks just like what I need. From 0 to app in the newest stack, would probably buy and try it if somebody does not have something better in mind?
No idea how good that book is but that newest stack won't be the newest in maybe a month or so. Assuming that is well written most of it will be applicable or will need only minor updating. That's probably why no iOS dev (from the original comment) can find anything "up to date" because we're right on the edge of a new release.
> Yeah, up-to-date was assumed in my post. I don`t want a post about Objective-C from 2012.
What a ridiculous statement. Most of those resources are excellent and relevant today. An article/blog post on calendrical or localization or accessibility is still as relegate today, as “back in the day” in 2012. This is not some web “dev” nonsense where the “stack” changes every year and a half. iOS and macOS consist of some tried and tested APIs that are decades old.
I suspect that with your Java, you'll find Swift to be a snap to get started in, particularly if you've also experimented ever with Scala. Mastering idiomatic Swift is a bit harder, but definitely doable with a bit of effort.
I think you'd pick up Swift pretty easily given your polyglot background, but if you already know javascript and you aren't doing something that screams to be native, RN would be my choice. You'll get to work in a familiar language, and get an Android version with much less work than if you do swift.
There is little “native” about React Native. It’s something web “devs” like to convince themselves because they don’t know better.
Using merely UIView objects does not mean it is native. It’s not just an abstraction over native. The “great” minds at Facebook have decided to not only offer a JS wrapper around the native APIs and objects, but actually reinvent the wheel on everything. Tables? Let’s have a horrible implementation in JS. Gestures? Slow ones in JS. Navigation? Absolutely terrible in JS. Animations? Core Animation you say? Nope, in JS or in C++. Even simple stuff like buttons are not native UIButton objects. There is nothing “native” in React Native.
Also, the single threaded model of JS just does not scale. The larger the app gets, the more and more it starts to lag. UI is rendering at 60 FPS, sure, but the lag comes from a constantly busy single JS thread.
And that’s before mentioning things like accessibility, large type support, basic iOS concepts such as margins and layout guides, etc. that are sorely missing from RN.
“I want to learn how to fly a Cessna where should I start?”
“I’d recommend hang gliding. That way, you don’t have to worry about the complexities of piston engines. Since you already know how to fly a kite, you’re practically there already.”
While hang gliders and Cessnas are both flying, there are a lot of things Cessna can do that hang gliders can’t.
I will be glad when JavaScript stops being the answer to every question. iOS apps aren’t just webpages running on a phone. How, for example, does react handle pre-release Apple APIs? How does it work with ARKit or other iOS specific tech?
Why do we insist on building to quite literally the lowest common denominator rather than building to the strengths of iOS and Android?
React Native could be a prudent choice for certain kinds of apps, but I’d argue that the apps for which React Native excels probably don’t need to be apps in the first place.
Apps ought not be glorified web pages; they should take advantage of the hardware to the fullest extent.
If an actual Swift developer recommends React Native, I might listen, but generally it’s web developers who downplay the advantages of Swift because they themselves have been unwilling to learn how to get the most out of it and the iOS APIs.
This whole cross-platform obsession results in lower quality applications. Case in point: Slack for Mac OS. It’s decent, but it would be significantly better if it were actually native. This trend of wrapping a webpage and calling it an app is a disservice to your customers.
There’s a reason I have an iPhone. Yet, with this cross-platform nonsense, developers are essentially kneecapping our devices. This applies to Android as well.
I evaluated react native and I really like what I saw and was on the edge to use it. BUT, I am still afraid that it will bite me somewhere in time where it will hurt much. For example, I want to build an app with 50% standard interface stuff and about 50% custom, with some animations throughout the interface. From what I gathered reading other people experiences it would be a bit of a pain in react native.
And the other smaller reason is that I want to build native macOS app that goes along with it and as far as I can tell from my own experience, only natively written apps feel good on osx. And just don`t mention Electron, I hate it.
I think it is best to write the "core" of your application using a language that can run on all of your target platforms -- which typically means you'll have to use C/C++/Rust or something similar that can be compiled to native code and supports somewhat sane FFI. The UI for each platform should be done using the Native UI toolkit for the platform. That way, you can avoid most of the code duplication.
If you plan to target Android, you might want to check out Google's Java to Objective-C transpiler[1]. That will let you write the core of the app in Java and transpire it to Objective-C for iOS and macOS. The UI will still have to be written using the native toolkit for the platform, though. Fair warning: I have no idea how good or bad it is -- never used it myself.
React-native animations have come a long way. I think your concerns are real, but you'd be pleasantly surprised. You might want to dip your toes, see how far you get in a day and how it feels.
IMO flutter.io looks a lot more promising (navigation isn't a mess, for example) but really native is the way to go. I'm biased towards native as that's what I do day to day.
React Native is more fun to work with than PhoneGap though (I've shipped apps with the latter and really hated it).
So, my question is. How hard and enjoyable is for someone like me to write not very complex native iOS/macOS app in Swift starting from scratch? Best resource to start with?