Can't seem to switch to another storyboard via a UIButton - ios11

When I'm trying to switch from one view to another using Swift 4 on XCode 9, it gives me this error.
libc++abi.dylib: terminating with uncaught exception of type
NSException
I'm using a button to switch from Main to LandingView. Main is the default view(main.storyboard) while LandingView is another view controller within main.storyboard.
Here's the code I'm using to get this to work.
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let newViewController = storyBoard.instantiateViewController(withIdentifier: "LandingView")
self.present(newViewController, animated: true, completion: nil)
[Above] All contained in a IBAction for the button I want to use.
Just to clarify, LandingView is a Storyboard ID that I'm using to make the switch from default view to LandingView. Please note this is all contained under Main.storyboard.

You haven't specified newViewController's type.
Try this:
let storyBoard: UIStoryBoard = UIStoryBoard(name: "Main", bundle: nil)
let newViewController = storyboard.instantiateViewController(withIdentifier: "LandingView") as! younewViewControllerType
self.present(newViewController, animated: true, completion: nil)
To determine what you have declared your LandingView ViewController Subclass, you can reference Identity Inspector in Interface builder as in the image below:
Under Custom Class, the Class property defines your custom subclass. When declaring your newViewController, you must declare it as that type.

Related

Pass array from AppDelegate to view controller

I'm loading an array with data from a Firebase database in my AppDelegate as I need the arrays loaded before the views are created and loaded. How can I pass this array to a view controller to populate a TableView?
Edit:
I don't think I worded my question correctly nor provided enough information. I have this Firebase data that I need to load into an array. This array needs to be loaded into the app before it is used by the view controller that uses the array. This is because the view controller uses a cocoa pod that splits the array into a number of categories to be displayed in different tableviews. The repo for the cocoa pod I'm using can be found here.
My question then is where is the best place to load this array? My first thought was the AppDelegate, but the array is empty and as such the table view doesn't load. I'm pretty new to iOS programming so I'm open to any and all suggestions.
In the AppDelegate class:
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
//Fill your array, let's say it's called firebaseArray. I would recommend doing so in the view controller and not in the Appdelegate for better responsibility distribution in your code
let vc = YourViewController()
//And YourViewController must have a array property
vc.array = firebaseArray
window = UIWindow(frame: UIScreen.main.bounds)
//make your vc the root view view controller
window?.rootViewController = vc
window?.makeKeyAndVisible()
return true
}

In Swift 4 Xcode 9, if you load and present a Nib as follows, how do you dismiss it?

In Swift 4 Xcode 9, if you load and present a Nib as follows, how do you dismiss it? This is an extract of my code in another ViewController from which the Nib gets loaded.
#objc func doPresent(_ sender: Any?) {
if let svc = Bundle.main.loadNibNamed("SecondViewController", owner: self, options: nil)?.first as? SecondViewController {
svc.data = "This is very important data!"
svc.delegate = self
self.present(svc, animated:true)
}
}
I tried:
self.view.subviews[0].removeFromSuperview()
and
self.view.removeFromSuperview()
as well as
self.dismiss(animated:true)
None of the three have the desired result. The first one removes a button from the Nib, the second just gives me a dark screen and the third dismisses the view in which the Nib is embedded to the original view in the navigation view.
I declared svc as a var at the class level and was able to use
self.v.removeFromSuperview()
That did the trick for me.

NSUnknownKeyException : was sent to an object that is not KVC-compliant for the "player" property

I have updated my code to swift 4 in Xcode 9. Before that it was working fine. But now AVplayer is crashing at observers below is the code where it is crashing.
addObserver(self, forKeyPath: "player.currentItem.duration", options: [.new, .initial], context: &playerViewControllerKVOContext)
And the log is
Terminating app due to uncaught exception
'NSUnknownKeyException',reason: '[ addObserver: forKeyPath:#"player.currentItem.duration" options:5
context:0x10ff74ac8] was sent to an object that is not KVC-compliant
for the "player" property.'
Swift does not have the Key value observer of its own so for Swift 4 we have to add:
#objc dynamic
before the property whose value you need to observe. In your case it will be the AVPlayer instance. e.g.:
class MyPlayerCustomView: UIView {
#objc dynamic var myPlayer: AVPlayer?
}
Hope this solves your problem. It did solve mine!

WatchKit how do I perform a specific segue with an identifier

I have a button that is already hooked up in the InterfaceBuilder to bring up a modal interface controller. In some cases I'd like to trigger this transition programmatically but I can't find a way to perform that same segue in Watchkit. I know you can do this in iphones/iOS but so far I can't find it in the Watchkit.
It can be done programatically. You need to set the Identifier in the storyBoard for the interface.
If you want it to present modally
presentControllerWithName("Identifier", context: nil)
If you want to push
pushControllerWithName("Identifier", context: nil)
You can set context if you like. You can retrieve it in the controller you push/present
override func awakeWithContext(context: AnyObject?) {
super.awakeWithContext(context)
}
the new calls:
presentController(withName: "Identifier", context: nil)
pushController(withName: "Identifier", context: nil)

Swift iOS. Program crashes when i try to mutate an array of buttons

I have about 20 buttons linked to allKeys. I want the turnRed button to change the color of their text to red. I tried the following code:
#IBOutlet var allKeys: [UIButton]!
#IBAction func turnRed(sender: UIButton) {
var i = allKeys.count
repeat {
allKeys[i].setTitleColor(UIColor.redColor(), forState: UIControlState.Normal)
i -= 1
} while i != -1
}
When I press the turnRed button, my program crashes and xcode jumps to the appDelegate file and highlights the AppDelegate class with the error Thread1: signal SIGABRT.
The console says "Terminating app due to uncaught exception 'NSRangeException Reason: NSArrayI objectAtIndex
The issue here is that you are setting the variable i to allKeys.count, but since arrays in swift start with zero, the twentieth element should actually be allKeys[19]. Thus, when the loop is at i = 20, it tries to access allKeys[20], which crashes the app.
One way to solve this is to set i to allKeys.count - 1 instead, but a better way would be to use a for-in loop instead of repeat.
for key in allKeys {
key.setTitleColor(UIColor.redColor(), forState: UIControlState.Normal)
}
There are multiple ways to loop in Swift, and you should use the options to your advantage. You can find Apple's documentation for Control Flow here.

Resources