So, my App (iOS, Swift 2.2, Xcode 7.3) got rejected by Beta App Review team because it crahsed on launch.
UPDATE Got an answer from the App Review Team
I got it approved.
UPDATE
While I got it approved, the next build of the app was rejected again, same reason, same sort of crash reports, again pointing to the first line of the viewDidLoad method.
I then radically threw all my code from viewDidLoad into viewWillAppear like this:
var viewLoaded = false
override func viewDidLoad() {
super.viewDidLoad()
// Do nothing
}
override func viewWillAppear(animated: Bool) {
if !viewLoaded {
// viewDidLoad code
viewLoaded = true
}
// viewWillAppear code
}
My theory now is that I discovered an Apple Bug:
I'm using storyboards and my rootViewController is very (very) heavy. Lots of UIVIews, UILabels, MapView, Buttons, Searcher, Embedded TableView etc. My guess is that it crashed because not all storyboard elements were initialised when viewDidLoad was called.
If this is indeed true (time will tell when I submit more builds for review) I think I either discovered a bug in iOS (as I should be able to reference IBOutlets from the storyboard in my viewDidLoad) or a discrepancy in the review process running the app, compared to actual devices running the app (as neither me nor any of my 400 beta testers is experiencing this crash).
END OF UPDATE
Based on RJE's comment I took another look at my AppDelegate to see if I was forcefully unwrapping something. I was, but to my knowledge these values could never be nil so I didn't give it another thought when I first coded it. I guess I should have.
In the build that finally got approved 3 things were different from the previous one that didn't get approved.
didFinishLaunchingWithOptions
I was forcefully unwrapping NSBundle.mainBundle().infoDictionary!["CFBundleVersion"]!
I changed
if UD.appVersion == nil || UD.appVersion != "\(NSBundle.mainBundle().infoDictionary!["CFBundleVersion"]!)" {
startClean()
UD.appVersion = "\(NSBundle.mainBundle().infoDictionary!["CFBundleVersion"]!)"
}
to this
var versionInInfoDictionary = "dummy"
if let infoDict = NSBundle.mainBundle().infoDictionary {
if let bundleVersion = infoDict["CFBundleVersion"] as? String{
versionInInfoDictionary = bundleVersion
}
else {
printError("bundleVersion nil")
}
}
else {
printError("infoDic nil")
}
if UD.appVersion == nil || UD.appVersion != versionInInfoDictionary {
startClean()
UD.appVersion = versionInInfoDictionary
}
applicationDidBecomeActive
I was forcefully unwrapping window
(defined in my AppDelegate class as var window: UIWindow?
)I changed
func applicationDidBecomeActive(application: UIApplication) {
// some code
let navController = window!.rootViewController as! CustomNavigationController
// some code
}
to this
func applicationDidBecomeActive(application: UIApplication) {
// some code
self.continueDidBecomeActive()
}
func continueDidBecomeActive() {
guard window != nil else {
printError("Window still nil")
NSTimer.scheduledTimerWithTimeInterval(0.3, target: self, selector: #selector(AppDelegate.continueDidBecomeActive), userInfo: nil, repeats: false)
return
}
if let navController = window!.rootViewController as? CustomNavigationController {
// some code
}
}
Now, I don't think it was the 3rd point that made my app crash for the App Review Team, otherwise it would have crashed on all devices and also for me.
So, it has to be either number 1, number 2 or both. Honestly I don't know and I'm still a bit confused as to why these values would be nil in any circumstance. If there are any more insights... I'd love to hear them.