Having trouble identifying the error when using the navigationController stack - ios

Description
So I decided to fire up my app once more, after doing a clean and reinstall, and found that I was getting a crash that would send me to a "Thread 1: signal SIGABRT" at the top of the AppDelegate.swift file. The error occurred when I was simply navigating through views, via buttons that show(push) on to the stack. I even tried commenting out the functions on the view that I was trying to reach, in order to insure that it wasn't a function throwing an error for some reason. Below, I will attach some code snippets connected with the view I am trying to reach and the view that I am currently on. Sorry if this seems vague. It is just a very vague issue I am running into.
Code
class back4: UIViewController, UITextFieldDelegate{
#IBOutlet weak var no: UIButton!
#IBOutlet weak var yes: UIButton!
#IBOutlet weak var distance: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
/*
#IBAction func save(_ sender: AnyObject) {
let appDel:AppDelegate = (UIApplication.shared().delegate as! AppDelegate)
let context:NSManagedObjectContext = appDel.managedObjectContext
let entity1 = NSEntityDescription.insertNewObject(forEntityName: "CrawlerOne", into:context) as NSManagedObject as! CrawlerOne
entity1.crawlerDistance = distance.text
}
#IBAction func yes(_ sender: AnyObject) {
let appDel:AppDelegate = (UIApplication.shared().delegate as! AppDelegate)
let context:NSManagedObjectContext = appDel.managedObjectContext
let entity1 = NSEntityDescription.insertNewObject(forEntityName: "CrawlerOne", into:context) as NSManagedObject as! CrawlerOne
entity1.crawlerAbrasion = "yes"
}
#IBAction func no(_ sender: AnyObject) {
let appDel:AppDelegate = (UIApplication.shared().delegate as! AppDelegate)
let context:NSManagedObjectContext = appDel.managedObjectContext
let entity1 = NSEntityDescription.insertNewObject(forEntityName: "CrawlerOne", into:context) as NSManagedObject as! CrawlerOne
entity1.crawlerAbrasion = "no"
}
*/
#IBAction func back(_ sender: AnyObject) {
if let navController = self.navigationController {
navController.popViewController(animated: true)
}
}
}
^ This is the code for the view that I am trying to reach, via a show segue connected to a button*
class back3: UIViewController, UITextFieldDelegate{
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func back(_ sender: AnyObject) {
if let navController = self.navigationController {
navController.popViewController(animated: true)
}
}
}
^ This is the code attached to the view I am currently at
Recap
Again, I don't get any error messages besides the "Thread 1: signal SIGABRT" at the top of AppDelegate.swift. I've also already checked for accidental multi-segue'd buttons, because I know I've accidentally done that in the past. I am using swift 3 and xcode 8.0
Debugger Console
2016-08-04 10:05:32.239 Prototype Inspection[9292:4560823] CUICatalog: Invalid asset name supplied
2016-08-04 10:05:32.241 Prototype Inspection[9292:4560823] Could not load the "" image referenced from a nib in the bundle with identifier "Wirtgen.Prototype-Inspection"
2016-08-04 10:05:33.732 Prototype Inspection[9292:4560823] CUICatalog: Invalid asset name supplied:
2016-08-04 10:05:33.733 Prototype Inspection[9292:4560823] Could not load the "" image referenced from a nib in the bundle with identifier "Wirtgen.Prototype-Inspection"
2016-08-04 10:05:34.609 Prototype Inspection[9292:4560823] CUICatalog: Invalid asset name supplied:
2016-08-04 10:05:34.610 Prototype Inspection[9292:4560823] Could not load the "" image referenced from a nib in the bundle with identifier "Wirtgen.Prototype-Inspection"
2016-08-04 10:05:35.981 Prototype Inspection[9292:4560823] Unknown class back4 in Interface Builder file.
2016-08-04 10:05:36.010 Prototype Inspection[9292:4560823] *** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[ setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key distance.'
*** First throw call stack:
(0x180a42db0 0x1800a7f80 0x180a42a70 0x18134f6e4 0x185f15de8 0x186078eb0 0x180966888 0x186077898 0x185f19230 0x185cde118 0x185ba08ec 0x185bb90d0 0x185d53e5c 0x185c5fe40 0x185c5fb1c 0x185c5fa84 0x185b9c1e4 0x18352e994 0x1835295d0 0x183529490 0x183528ac0 0x183528820 0x185b9eff4 0x1809f909c 0x1809f8b30 0x1809f6830 0x180920c50 0x182208088 0x185c0a088 0x1000ad4c8 0x1804be8b8)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)

The view controller that you're navigation to has an outlet for distance hooked up in the storyboard, but a distance property doesn't (or no longer) exists on the destination view controller's class. It says that no back4 class could be found. Make sure that in the view controller's identity inspector, it has the correct module set below the class name. Sometimes Xcode fails to infer the correct module, and you have to set it manually.

Related

Swift audio playing from url

import AVFoundation
import UIKit
class ViewController: UIViewController {
#IBOutlet var button: UIButton!
var player: AVPlayer?
var playerItem:AVPlayerItem?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func didTapButton(urlRadio: String){
if let player = player, player.isMuted{
//stop playback
}
else{
do {
try AVAudioSession.sharedInstance().setMode(.default)
try AVAudioSession.sharedInstance().setActive(true, options: .notifyOthersOnDeactivation)
guard let urlRadio = URL.init(string: "http://live.shtorm.fm:8000/mp3_rushtorm") else {
return
}
let playerItem:AVPlayerItem = AVPlayerItem.init(url: urlRadio)
player = AVAudioPlayer.init(playerItem: playerItem)
}
catch {
print("something went wrong")
}
}
}
}
shows error Exception NSException * "-[RozetkaRadio.ViewController didTapButton]: unrecognized selector sent to instance 0x7ff070f07a50" 0x00006000008c7210 after pressing button in emulator
using storyboard
Your issue is with this line of code. Specifically, the parameter urlRadio.
#IBAction func didTapButton(urlRadio: String){
It looks like you have changed the standard IBAction from what was set in storyboard. You cannot change the parameters in an IBAction as the storyboard no longer recognizes where to send the tap to.
Your IBAction should look something like this
#IBAction func didTapButton(_ sender: Any)
Whenever you see Unrecognized selector sent to instance you should immediately think "Something is not hooked up properly between my storyboard and my ViewController"
One quick way to look is by right clicking your controller scene name on the storyboard. You can see I commented out my SignIn IBAction function. If I wanted to remove it I would have to also remove the connection on the storyboard. You can see the storyboard will let me know by leaving a yellow warning label.

"unrecognized selector sent to instance" when selector is in other file

Here is the problematic ViewController class.
class ViewController: UIViewController {
#IBOutlet weak var photoSelectActionSheet: UIButton!
#IBOutlet weak var selectedImageView: UIImageView!
var imagePicker: UIImagePickerController!
var selectedImage: UIImage? = ni
var iCloud = ICloud() // see below for code of that file
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Must use this system to check each time the view appears.
// This is checked each time so if user goes into settings and come back in same session
// then this will be updated => viewDidLoad is cached and not reloaded each time.
NotificationCenter.default.addObserver(
self,
selector:#selector(ICloud.checkIfUserIsLoggedInIcloud), // PROBLEM IS HERE
name: UIApplication.didBecomeActiveNotification,
object: nil)
}
// more code not shown
}
Problem is in viewWillAppear: the notification center calls a selector that is in an other Model file ICloud.swift:
import UIKit
import CloudKit
class ICloud {
var isLoggedInIcloud: Bool? = nil
var userIcloudId: String? = nil
func getUserIcloudId() {
// Run this only if user is logged into icloud, and we don't have yet its iCloud id.
if isLoggedInIcloud ?? false && userIcloudId == nil {
CKContainer.default().fetchUserRecordID(completionHandler: { (recordId, error) in
if let id = recordId?.recordName {
print("userIcloudId set to: " + id)
self.userIcloudId = id
}
else if let error = error {
print(error.localizedDescription)
}
})
}
}
#objc func checkIfUserIsLoggedInIcloud() {
// Check if user is logged into iCloud
CKContainer.default().accountStatus { accountStatus, error in
if accountStatus == .available {
self.isLoggedInIcloud = true
print("isLoggedInIcloud set to true")
self.getUserIcloudId()
return
}
print("User is not logged into icloud")
}
}
}
I expected "ICloud.checkIfUserIsLoggedInIcloud" passed in selector to work. It doesn't:
2020-07-01 11:46:12.931419+0200 QDog[53348:3422745] -[QDog.ViewController checkIfUserIsLoggedInIcloud]: unrecognized selector sent to instance 0x7fcad5f0c1d0
2020-07-01 11:46:12.938567+0200 QDog[53348:3422745] *** Terminating app due to uncaught exception
If I add back the functions and variables from ICloud.swift directly into the ViewController file and pass to the selector "checkIfUserIsLoggedInIcloud" it WILL WORK properly.
I wanted to put all icloud code into a separate model file for separation of concerns and to make the code more clear.
Question is: why does 'ICloud.checkIfUserIsLoggedInIcloud' passed as selector doesn't work? And how to make this work with ICloud code in its own file, and not in ViewController file?
According to the documentation, the first parameter should be the observer, which in your case you're pointing to self.
In this case, self is your ViewController, which doesn't have the method checkIfUserIsLoggedInIcloud. In order to make it work, as an observer, you need to pass the property iCloud instead of self.

UISplitViewController extension makes trouble for the app

I have a simple extension for UISplitViewController:
extension UISplitViewController {
var masterViewController: UIViewController? {
return (viewControllers.first as? UINavigationController)?.topViewController
}
}
Within some UIViewController I did connect modal segue to my UISplitViewController. When segue is being performed then I prepare my destinationViewController like this:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let searchResultsViewController = (segue.destinationViewController as? UISplitViewController)?.masterViewController as? SearchResultsViewController {
searchResultsViewController.mode = mode
}
}
And it DOESNT WORK because of error:
*** Terminating app due to uncaught exception 'NSGenericException', reason: 'The content view controller argument must be the root of its associated view controller hierarchy.'
However when I remove extension for UISplitViewController and prepare destinationViewController like this:
if let searchResultsViewController = ((segue.destinationViewController as? UISplitViewController)?.viewControllers.first as? UINavigationController)?.topViewController as? SearchResultsViewController {
//prepare controller
}
IT WORKS
What is the reason that it is not working in first case?
Try changing the name of your computed variable from masterViewController to something else. It seems you are overriding an internal property of the UISplitViewController.
This works and is not called during the setup of the UISplitViewController.
var masterVC: UIViewController? {
return (viewControllers.first as? UINavigationController)?.topViewController
}
This is called by something in the SDK and causes a crash.
var masterViewController: UIViewController? {
return (viewControllers.first as? UINavigationController)?.topViewController
}

Passing data between controllers - unexpectedly found nil while unwrapping an Optional

I am attempting a very simple task of passing data between two view controllers. I have control-dragged the label into the proper class and allowed the segues to populate with the correct data. Upon clicking the row, the prepareForSegue action is as:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "individualChat" {
if let indexPath = tableView.indexPathForSelectedRow {
let friend: Friend
friend = mappedFriends[indexPath.row]
let controller = segue.destinationViewController as! IndividualChatController
controller.friendChat = friend
}
}
}
and into the residing view controller:
import UIKit
class IndividualChatController: UIViewController {
#IBOutlet weak var anotherTestLabel: UILabel!
var friendChat: Friend! {
didSet {
configureView()
}
}
func configureView() {
if let friendChat = friendChat {
anotherTestLabel.text = friendChat.name as? String
}
}
}
Yet, upon clicking the row, the error appears:
fatal error: unexpectedly found nil while unwrapping an Optional value
on line:
anotherTestLabel.text = friendChat.name as? String
How can this be fixed?
Additional Screen Capture:
When you execute some code in prepareForSegue the next view is not loaded yet so all your outlets are still set to nil; because of this when you try to implicitly unwrap the content of anotherTestLabel at
anotherTestLabel.text = friendChat.name as? String
you get that error.
You can check if your label has been loaded and only if that's the case set its text using
anotherTestLabel?.text = friendChat.name as? String
and then manually calling configureView() in viewDidLoad() of IndividualChatController to proper load the label.
The added ? will check if your label is nil, if so nothing will be done, else it will proceed unwrapping the label and setting the text.

Passing object between view controllers in Swift

I am having a strange issue. I am trying to pass an object from ViewControllerA to CreateInvitationViewController.
In ViewControllerA I have following code:
func btnPassedRequestTouched(sender:UIButton!)
{
print("button passed request touched")
// pass request
self.performSegueWithIdentifier("createInvitationSegue", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
if segue.identifier == "createInvitationSegue" {
let createInvitationView = segue.destinationViewController as! CreateInvitationViewController
let invitation = invitations[self.carousel.currentItemIndex]
createInvitationView.invitation = invitation
}
}
I put a breakpoint on this line: createInvitationView.invitation = invitation, and I can see that this object exists.
In ViewControllerB I have the following code:
class CreateInvitationViewController: UIViewController {
var invitation = Invitation()
override func viewDidLoad() {
super.viewDidLoad()
// if invitation is set, then use it to populate fields
if let _ = self.invitation.id {
invitationText.hidden = false
invitationText.text = self.invitation.note
}
}
I am using Show action on the segue that I made and it looks like this:
This is the error that I am getting:
Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<MyProject.CreateInvitationViewController 0x156365810> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key postRequest.'
Do you have some suggestion why this happens?
It's telling you it cannot find postRequest. That means that you either have some code that is trying to set postRequest or, more likely, you have some control in your storyboard that is trying to connect to an outlet called postRequest, but no such outlet exists (e.g. maybe you had some outlet with that name in the past, removed the outlet from the code, but neglected to update the storyboard accordingly).

Resources