I have application that works well on ios8. However after updating everything to ios9 I am having problem with nill values. I cant figure out what value is nil. Here is the code:
func resetToChosenPage(index: Int!) {
/* Getting the page View controller */
pageViewController = self.storyboard?.instantiateViewControllerWithIdentifier("PageViewController") as! UIPageViewController
self.pageViewController.dataSource = self
pageContentViewController = self.viewControllerAtIndex(index)
if pageContentViewController != nil {
self.pageViewController.setViewControllers([pageContentViewController], direction: UIPageViewControllerNavigationDirection.Forward, animated: true, completion: nil)
}
/* We are substracting 30 because we have a start again button whose height is 30*/
self.pageViewController.view.frame = CGRectMake(0, self.navigationController!.navigationBar.frame.height , self.view.frame.width, self.view.frame.height - 30)
self.addChildViewController(pageViewController)
self.view.addSubview(pageViewController.view)
self.pageViewController.didMoveToParentViewController(self)
}
func viewControllerAtIndex(index : Int) -> UIViewController? {
if((dataArray.count == 0) || (index >= dataArray.count)) {
return nil
}
let pageContentViewController = self.storyboard?.instantiateViewControllerWithIdentifier("SingleArticleViewController") as! SingleArticleViewController
self.delegate = pageContentViewController
pageContentViewController.delegate = self
// pageContentViewController.delegateWebView = self
pageContentViewController.singleArticleIndex = index
pageContentViewController.categoryID = categoryID
pageContentViewController.dateOfPub = dataArray[index].pubDate
pageContentViewController.category = dataArray[index].category
pageContentViewController.newsTitle = dataArray[index].pageTitle
pageContentViewController.videoLink = dataArray[index].videoLink
return pageContentViewController
}
One line self.pageViewController.SetViewControllers([pageContentViewController]... I have error "fatal error: unexpectedly found nil while unwrapping an Optional value". The fact is this code works well on ios8. I checked and could not find nil values. Moreover, I checked all identifiers of storyboard but they are correct. Guys, what can be a problem if this code works on ios8?
I suggest try changing the if clause that wraps the setViewControllers: call so that it explicitly checks for both the pageContentViewController and the pageViewController:
if let pageVC = self.pageViewController, let contentVC = self.pageContentViewController {
pageVC.setViewControllers([contentVC], direction: UIPageViewControllerNavigationDirection.Forward, animated: true, completion: nil)
}
As a general thing, I would try to avoid using Implicitly Unwrapped Optionals (like that Int! in your resetToChosenPage: method. As they lead to these 'unexpectedly found nil' errors.
Also, since your resetToChosenPage: method doesn't check if the pageViewController has already been instantiated, calling it multiple times will result in many instances of the PageViewController being instantiated and piled on top of each other. Which is probably not what you want.
Related
I set the Show Charts button on the DetailView Controller which triggers the getChartData function and shows me the values in display view in charts, now I want to call that function in the didselectrow on the main Viewcontroller so that the chart is loaded automatically, but it fails.
When I tried to call that function in didselectrow (DVC.getChartsData) I got the error "Thread 1: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value"
DVC.getChartsData
Thread 1: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value
ViewController:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let Storyboard = UIStoryboard(name: "Main", bundle: nil)
let DVC = Storyboard.instantiateViewController(withIdentifier: "DetailViewController") as! DetailViewController
DVC.getDetailName = coin[indexPath.row].name
let formatedRoundingPrice = (coin[indexPath.row].price as NSString).floatValue * currencymodel.indexValue
let formatedPrice = String (format: "%.3f", formatedRoundingPrice)
DVC.getDetailPrice = formatedPrice
self.navigationController?.pushViewController(DVC, animated: true)
let percentage = String ((coin[indexPath.row].percent as NSString).floatValue)
DVC.getDetailPercent = percentage
tableView.deselectRow(at: indexPath, animated: true)
//DVC.getChartData()
}
DetailViewController:
#IBAction func tapLineChart(_ sender: Any) {
getChartData()
}
func getChartData () {
let chart = HITLineChartView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: displayView.bounds.height))
displayView.addSubview(chart)
let max = String((priceResult.max() ?? 0.0).rounded(.up))
let min = String((priceResult.min() ?? 0.0).rounded(.down))
let maxChange = abs((listOfChanges.max()) ?? 0.0).rounded(.up)
let minChange = abs((listOfChanges.min()) ?? 0.0).rounded(.up)
absMaxPercentage = Int(maxChange > minChange ? maxChange : minChange)
titles = ["\(getDetailName) closing price is \(getDetailPrice)"]
print(data)
chart.draw(absMaxPercentage,
values: listOfChanges,
label: (max: max, center: "", min: min),
dates: namesArray,
titles: titles)
addCloseEvent(chart)
finalURL = baseURL + "bitcoin" + "/market_chart?vs_currency=usd&days=5"
print(finalURL)
getBitcoinData(url: finalURL)
}
How to load my charts tap on a specific tableview cell instead of tapping on tapLineChart.
https://imgur.com/fg2502P
https://imgur.com/C4AzaRY
https://imgur.com/jOrwujy
if you want to call a function on viewControllerB that you declare from viewController A.
just create the object of the class file you want to use the function from
var obj mainVC = MainViewController()
class MainViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
func commonMethod() {
print("From the main class")
}
}
Using that object, call the function in another file where you mean to use it
class OtherViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
mainVC.commonMethod()
// Do any additional setup after loading the view, typically from a nib.
}
}
Additionally, You can also create a new swift file, name it Global.swift, create all your functions that you want to use throughout the application here. They become "global functions"
You will want to use delegates or observers to pass data between view controllers.
I'm new to tutorials, but I wrote a bit about this here: https://www.eankrenzin.com/swift-blog/pass-data-throughout-your-app-with-observers-and-notifications-xcode-11-amp-swift-5
You should use optional binding to unwrap your VC let DVC = Storyboard.instantiateViewController(withIdentifier: "DetailViewController") as! DetailViewController
Your code is crashing because of that line. Check your interface builder to make sure the identifier is correct. Edit: this line was not causing a crash, but it is still better to use optional binding.The line is: https://imgur.com/CVP1x6H
NOTE: It is terrible practice to litter your app with instances when delegates and observers could work. Also do NOT have globals. Globals are disastrous for debugging and create tech debt.
I am integrating TouchBar support to my App. I used the how to from Rey Wenderlich and implemented everything as follows:
If self.touchBarArraygot filled the makeTouchBar() Method returns the NSTouchBar object. If I print out some tests the identifiers object is filled and works.
What not work is that the makeItemForIdentifier method not get triggered. So the items do not get created and the TouchBar is still empty.
Strange behavior: If I add print(touchBar) and a Breakpoint before returning the NSTouchBar object it works and the TouchBar get presented as it should (also the makeItemForIdentifier function gets triggered). Even if it disappears after some seconds... also strange.
#available(OSX 10.12.2, *)
extension ViewController: NSTouchBarDelegate {
override func makeTouchBar() -> NSTouchBar? {
if(self.touchBarArray.count != 0) {
let touchBar = NSTouchBar()
touchBar.delegate = self
touchBar.customizationIdentifier = NSTouchBarCustomizationIdentifier("com.TaskControl.ViewController.WorkspaceBar")
var identifiers: [NSTouchBarItemIdentifier] = []
for (workspaceId, _) in self.touchBarArray {
identifiers.append(NSTouchBarItemIdentifier("com.TaskControl.ViewController.WorkspaceBar.\(workspaceId)"))
}
touchBar.defaultItemIdentifiers = identifiers
touchBar.customizationAllowedItemIdentifiers = identifiers
return touchBar
}
return nil
}
func touchBar(_ touchBar: NSTouchBar, makeItemForIdentifier identifier: NSTouchBarItemIdentifier) -> NSTouchBarItem? {
if(self.touchBarArray.count != 0) {
for (workspaceId, data) in self.touchBarArray {
if(identifier == NSTouchBarItemIdentifier("com.TaskControl.ViewController.WorkspaceBar.\(workspaceId)")) {
let saveItem = NSCustomTouchBarItem(identifier: identifier)
let button = NSButton(title: data["name"] as! String, target: self, action: #selector(self.touchBarPressed))
button.bezelColor = NSColor(red:0.35, green:0.61, blue:0.35, alpha:1.00)
saveItem.view = button
return saveItem
}
}
}
return nil
}
}
self.view.window?.makeFirstResponder(self) in viewDidLoad() did solve the problem.
i am trying to use UIImagepickerController to pick an image from photos.
I am using the function below in my gameScene class
(this is for importing images into a game)
But I get the error "Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value"
on this line
self.view!.window!.rootViewController!
the function is below. I am not sure how to fix it and have searched for an answer without much luck, so any help would be great.
func getPhotoFromSource(source:UIImagePickerControllerSourceType ){
if UIImagePickerController.isSourceTypeAvailable(source)
{
let imagePicker = UIImagePickerController()
imagePicker.modalPresentationStyle = .currentContext
imagePicker.delegate = self
imagePicker.sourceType = source
imagePicker.allowsEditing = false
if (source == .camera){
imagePicker.cameraDevice = .front
}
let vc:UIViewController = self.view!.window!.rootViewController! //Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value
vc.present(imagePicker, animated: true, completion: nil)
} }
instead of
let vc:UIViewController = self.view!.window!.rootViewController!
, use optional chaining and try
guard let vc = self.view?.window?.rootViewController else {
print("something went wrong")
}
Seeing how it's either your view or your window or your rootViewController that's not there when you try to force unwrap, if you run the code above your code will just run the print statement above.
Can you share your code for setting up your viewController?
I have this code to pass info between viewControllers using protocols, I have my models and with the first protocol work perfectly but the second one I have some issues, the data pass nil, or do nothing, already use tabBarController & UINavigationBar... the protocols... I create one in my ViewController(RecordViewController) and have the button & action and one protocol, this is:
protocol RecordViewProtocol {
func newTrackInstrument(item: SampleCarouselsRecord)
func newInstrumentTrackCell(item: SampleTrackCellRecord)
}
extension RecordViewController: RecordViewProtocol {
func newTrackInstrument(item: SampleCarouselsRecord) {
self.sampleCarouselItemsRecord.append(item)
let indexOnPath = NSIndexPath(row: self.sampleCarouselItemsRecord.count - 1, section: 0)
self.instrumentCarousel.insertItems(at: [indexOnPath as IndexPath])
}
func newInstrumentTrackCell(item: SampleTrackCellRecord) {
self.sampleTrackRecord.append(item)
let indexOnPath = NSIndexPath(row: self.sampleTrackRecord.count - 1, section: 0)
self.trackInstrument.insertItems(at: [indexOnPath as IndexPath])
}
}
the other protocol, on another ViewController(MixerViewController):...
protocol MixerViewProtocol {
func newCarouselItem(item: SampleCarouselMixer)
}
extension MixerViewController: MixerViewProtocol {
func newCarouselItem(item: SampleCarouselMixer) {
self.sampleCarouselMixer.append(item)
let indexOnPath = NSIndexPath(row: self.sampleCarouselMixer.count - 1, section: 0)
self.mixerCarouselInstrument.insertItems(at: [indexOnPath as IndexPath])
}
}
so, when wanna go the view and put the info to my models.. I put this code in the action Button to go into the view where is the function to put the info models:
#objc func goToAddView() {
let addTrackViewController = AddNewTrackView()
let addTrackView = UINavigationController(rootViewController: addTrackViewController)
addTrackViewController.recordViewControllerProtocol = self as RecordViewProtocol
present(addTrackView, animated: true, completion: nil)
}
and work good with the first protocol.. but with to the other protocol nothing.. I don't know why or I don't know wath I have to do... look, I have the delegate protocols inside on the AddNweTrackView:
var recordViewControllerProtocol: RecordViewProtocol?
var delegateMixerView: MixerViewProtocol? <- this is I think, put into the action button like the firstone:
here on the same action where the first protocol already is
#objc func goToAddView() {
let addTrackViewController = AddNewTrackView()
let addTrackView = UINavigationController(rootViewController: addTrackViewController)
addTrackViewController.recordViewControllerProtocol = self as RecordViewProtocol
addTrackViewController.delegateMixerView = MixerViewController.self as? MixerViewProtocol
present(addTrackView, animated: true, completion: nil)
}
but return nil... and I try with diferents forms.. I try put this:
let mixerViewController = MixerViewController()
addTrackViewController.delegateMixerView = mixerViewController as? MixerViewProtocol
and try with this but the error Is obvious:
addTrackViewController.delegateMixerView = self as MixerProtocol
and the same... I think, here at this point, it's where Im failing .. someone can help?
Good day guys, I'm learning Swift, needed some help here.
The user are signing up and selected their image. Upon dismissing the image picker, I would like to have the ComposeViewController appear.
Here is the code:
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: NSDictionary!) {
let pickedImage:UIImage = info.objectForKey(UIImagePickerControllerOriginalImage) as UIImage
//Scale Down Image
let scaledImage = self.scaleImageWith(pickedImage, and: CGSizeMake(100,100))
let imageData = UIImagePNGRepresentation(scaledImage)
let imageFile:PFFile = PFFile(data: imageData)
PFUser.currentUser().setObject(imageFile, forKey: "profileImage")
PFUser.currentUser().saveInBackgroundWithTarget(nil, selector: nil)
picker.dismissViewControllerAnimated(true, completion: nil)
//this is the line seems to have problem.
self.navigationController?.popToViewController(ComposeViewController, animated: true)
}
Then I got these error:
ComposeViewController.Type' is not convertible to 'UIViewController
Expected member name or constructor call after type name
It has suggestion to fix by putting () after ComposeViewController but then it gives out more errors after fixing.
Hope someone could help. Thanks! :-)
let controllers = self.navigationController?.viewControllers
for vc in controllers! {
if vc is YourVC {
_ = self.navigationController?.popToViewController(vc as! YourVC, animated: true)
}
}
I know this is old, but it's like what Saqib said, you can't pop to a viewcontroller that doesn't exist yet.
A lot of the answers here seem to be from people that didn't read your question, just the title. I'll leave this code here in case it helps anyone.
let vcIndex = self.navigationController?.viewControllers.indexOf({ (viewController) -> Bool in
if let _ = viewController as? ComposeViewController {
return true
}
return false
})
let composeVC = self.navigationController?.viewControllers[vcIndex!] as! ComposeViewController
self.navigationController?.popToViewController(composeVC, animated: true)
There's a method that lets you get access to an array of all the ViewControllers on the current stack, and you can capture the one you want by using its index, for instance:
let switchViewController = self.navigationController?.viewControllers[1] as! ComposeViewController
self.navigationController?.popToViewController(switchViewController, animated: true)
if let composeViewController = self.navigationController?.viewControllers[1] {
self.navigationController?.popToViewController(composeViewController, animated: true)
}
I ended up replaceing the following code inside the main view and it works. I'm not sure if this is the right way, would you mind giving me some comments?
//self.navigationController?.popToViewController(ComposeViewController, animated: true)
let switchViewController = self.storyboard?.instantiateViewControllerWithIdentifier("view2") as ComposeViewController
self.navigationController?.pushViewController(switchViewController, animated: true)
I defined "view2" as the destination storyboard ID.
What I found more useful was to do a first lookup with viewControllers, that way you get the first instance you find in the stack, without having to guess the actual index.
e.g.
let mainViewControllerVC = self.navigationController?.viewControllers.first(where: { (viewcontroller) -> Bool in
return viewcontroller is ComposeViewController
})
if let mainViewControllerVC = mainViewControllerVC {
navigationController?.popToViewController(mainViewControllerVC, animated: true)
}
For Swift 4.0 and above Using Filter
guard let VC = self.navigationController?.viewControllers.filter({$0.isKind(of: YourViewController.self)}).first else {return}
self.navigationController?.popToViewController(VC, animated: true)
navigation controller maintains the stack of views you are pushing. Its like a Last in first out queue.
In order to pop to ComposeViewController, that view must already exist in the queue and you should have reference to it.
You will need to pass the instance of ComposeViewController. for simplicity you might save that reference in appdelegate. (this approach is not recommended)
for (var i = 0; i < self.navigationController?.viewControllers.count; i++)
{
if(self.navigationController?.viewControllers[i].isKindOfClass(DestinationViewController) == true)
{
self.navigationController?.popToViewController(self.navigationController!.viewControllers[i] as! DestinationViewController, animated: true)
break;
}
}
In Swift 4.1 and Xcode 9.4.1
Suppose if you moved from 1st ViewController to 2nd, then 2nd to 3rd. Now if you want to come back from 3rd to 1st directly this code is enough.
if let composeViewController = self.navigationController?.viewControllers[1] {//Here you mention your view controllers index, because navigation controller can store all VC'c in an array.
print(composeViewController)
self.navigationController?.popToViewController(composeViewController, animated: true)
}