what to recast as an NSSplitViewItem - swift

I am trying to self-learn OSX application development so I can make up all of my own bad habits 8).
Probably extraneous information
I have a trial app that works successfully - it resizes itself based on input from the user via a slider.
The key piece of code that does this is in one View controller ...
class JunkViewController2: NSViewController {
var myY: CGFloat!
#IBOutlet weak var mySlider: NSSlider!
#IBOutlet weak var myView: NSView!
override func viewDidLoad() {
super.viewDidLoad()
// Do view setup here.
self.preferredContentSize = NSMakeSize(self.view.frame.width, 83)
}
#IBAction func mySlider(sender: NSSlider) {
let mySplitViewController = self.childViewControllers[0] as! JunkSplitViewController
switch mySlider.intValue {
case 3:
myY = 140.0
mySplitViewController.splitViewItems[2].collapsed = false
mySplitViewController.splitViewItems[1].collapsed = false
mySplitViewController.showSubview(2)
mySplitViewController.showSubview(1)
mySplitViewController.showSubview(0)
case 2:
myY = 110.0
mySplitViewController.splitViewItems[2].collapsed = true
mySplitViewController.splitViewItems[1].collapsed = false
mySplitViewController.hideSubview(2)
mySplitViewController.showSubview(1)
mySplitViewController.showSubview(0)
default:
myY = 80.0
mySplitViewController.splitViewItems[2].collapsed = true
mySplitViewController.splitViewItems[1].collapsed = true
mySplitViewController.hideSubview(2)
mySplitViewController.hideSubview(1)
mySplitViewController.showSubview(0)
}
mySplitViewController.preferredContentSize = NSMakeSize(self.view.frame.width, myY - 50 + 3)
self.preferredContentSize = NSMakeSize(self.view.frame.width, myY + 3)
}
}
More pertinent information
In what is working, above, on the story board I have three duplicate ViewControllers connected to a SplitView controller. I do a bunch of what feels like belts and suspenders work to make sure that everything gets resized properly - but the key part (I think) is the .collapsed property.
I am now trying to accomplish the same thing, using a completely different method - dynamically adding / removing split view items. This should allow me to have only one of the small ViewControllers on my story board, and then instantiate it as needed.
Following that idea, here is my SplitViewController ...
class JunkSplitViewController: NSSplitViewController {
#IBOutlet weak var mySplitView: NSSplitView!
override func viewDidLoad() {
super.viewDidLoad()
// Do view setup here.
//mySplitView.adjustSubviews()
}
func makeChild() -> SmallViewController {
let mySmallGroup = NSStoryboard(name: "Main", bundle: nil).instantiateControllerWithIdentifier("smallVwCtl")
self.addSplitViewItem(mySmallGroup as! NSSplitViewItem)
return mySmallGroup as! SmallViewController
}
}
The main view controller invokes the makeChild function.
class JunkViewController: NSViewController {
#IBOutlet weak var mySlider: NSSlider!
#IBOutlet weak var myView: NSView!
override func viewDidLoad() {
super.viewDidLoad()
// Do view setup here.
self.preferredContentSize = NSMakeSize(self.view.frame.width, 83)
}
#IBAction func mySlider(sender: NSSlider) {
let mySplitViewController = self.childViewControllers[0] as! JunkSplitViewController
while mySlider.intValue.toIntMax() > mySplitViewController.splitViewItems.count.toIntMax() {
mySplitViewController.makeChild()
}
while mySlider.intValue.toIntMax() < mySplitViewController.splitViewItems.count.toIntMax(){
mySplitViewController.splitViewItems.removeLast()
}
}
}
I get an error at the self.addSplitViewItem(mySmallGroup as! NSSplitViewItem) line of JunkSplitViewController ... "Could not cast value of type Scratch2.SmallViewController to NSSplitViewItem"
I've tried a handful of combinations (forcing mySmallGroup, 'self.addSplitViewItem(mySmallGroup as! SmallViewController)`, etc.) Everything leads to a similar error, either at compile or run time.
I cannot find any documentation on SplitViewItem.
So the question - what will work as input to addSplitViewItem and still successfully connect a new instance of SmallViewController?
And gratefully accept any comments/feedback on the methodology

I hate it when I find my answer minutes after posting a question ...
Based on info I found here ...
func makeChild() -> SmallViewController {
let mySmallGroup = NSStoryboard(name: "Main", bundle: nil).instantiateControllerWithIdentifier("smallVwCtl") as! SmallViewController
self.addSplitViewItem(NSSplitViewItem(viewController: mySmallGroup))
return mySmallGroup
}
... but I'd still like to hear any feedback on methodology. Thanks.

Related

How to solve the error SIGABRT even if the outlets look correct?

I'm working on my first iOS app with Xcode and Swift. My app has multiple UIViewControllers (=VC). Everything works quite well, but there is an error which I couldn't work out on my own with the help of Google or StackOverflow.
My problem is:
I have a UIButton called 'Quit' in the VC 'CompleteTest' which I control dragged in the Main storyboard to the VC 'Main Menu' in order that it brings the user back to the 'Main Menu' when it is pressed.
But when I click this UIButton in the Simulator the error:
Thread 1 signal SIGABRT comes up.
This is not the first time I stumbled over this error and I saw multiple threads in stack overflow giving a solution to this problem. In the past by checking the outlets I could solve this error quite easily.
But in this case this solution doesn't work, because the outlets look fine (there are no exclamation-points showed).
What is even more strange is where the error is showed.
Normally the SIGABRT error is shown in the AppDelegate, if I'm not mistaken.
But in my case it is shown at the line 54 of the VC 'CompleteTest'-file. At this line I am transferring data to the next VC 'Final Complete test' with the override function 'prerpare'.
Unfortunately, I couldn't put images in this question, even tough
I prepared them. Anyway I hope my problem is still clear.
Furthermore, excuse me for my poor English as it is my second language.
How should I proceed? Thank you in advance for your help!
import UIKit
class CompleteTest: UIViewController {
// Components of Visualisation VC
#IBOutlet weak var ShotNumber: UILabel!
#IBOutlet weak var ProjectedScore: UILabel!
#IBOutlet weak var Distance: UILabel!
var sum: Double = 100.0 //sum represents overall Score of Test
#IBOutlet weak var Report: UIButton!
var help: Int = 0 // var 'help' is helping to change the number showed on the Scoring Buttons in VC
#IBOutlet weak var Left1: UIButton!
#IBOutlet weak var Right1: UIButton!
#IBOutlet weak var Center1: UIButton!
#IBOutlet weak var BadContact1: UIButton!
//Percentage components
var leftpct: Int = 0
var rightpct: Int = 0
var centerpct: Int = 0
var totalpct: Int = 0
var badcontactpct: Int = 0
// Transfer of data from ViewController 'CompleteTest' to ViewController 'FinalCompleteTest'
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let finalCompleteTest = segue.destination as! FinalCompleteTest
finalCompleteTest.score = String(sum)
finalCompleteTest.Leftpct = Int(leftpct)
finalCompleteTest.Rightpct = Int(rightpct)
finalCompleteTest.Centerpct = Int(centerpct)
finalCompleteTest.Totalpct = Int(totalpct)
finalCompleteTest.BadContactpct = Int(badcontactpct)
}
override func viewDidLoad() {
super.viewDidLoad()
Report.isHidden = true
}
//Scoring Buttons
#IBAction func BadContact(_ sender: Any) {
sum -= 1
BadContact1.setTitle("OK", for: .normal)
badcontactpct += 1
}
#IBAction func Left(_ sender: Any) {
sum -= 0.5
help += 1
Left1.setTitle(String(help), for: .normal)
if help == 1 {
leftpct += 1
totalpct += 1}
}
#IBAction func Right(_ sender: Any) {
sum -= 0.5
help += 1
Right1.setTitle(String(help), for: .normal)
if help == 1 {
rightpct += 1
totalpct += 1}
}
#IBAction func Center(_ sender: Any) {
Center1.setTitle("0", for: .normal)
centerpct += 1
totalpct += 1
}
Thanks for taking the time to write such a thorough question. If you want, you can upload your images to some other site (e.g. imgur) and then use the direct links here.
As matt mentions in the comments, that as! might be the reason you're seeing this crash. You can easily prove it if you replace your code to something like this:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let finalCompleteTest = segue.destination as? FinalCompleteTest {
finalCompleteTest.score = String(sum)
finalCompleteTest.Leftpct = Int(leftpct)
finalCompleteTest.Rightpct = Int(rightpct)
finalCompleteTest.Centerpct = Int(centerpct)
finalCompleteTest.Totalpct = Int(totalpct)
finalCompleteTest.BadContactpct = Int(badcontactpct)
} else {
print("oh no, segue.destination is not a FinalCompleteTest")
}
}
If you can see that message in your console, probably you haven't connected something correctly on the storyboard.
If not, try to give us some more information.
If you don't understand the "dangers" of using ! in your code, please try to understand Optionals first and don't hesitate to ask if you need more help.
Good luck!

views are merged instead of showing them separately

I have two xib file, one which shows login view and another which shows the steps what to do after the login is successful. I am having hard time to make it work. I have created macos project not ios and using safariservices so that it will work for the safari extension either.
Here is what i have done
import SafariServices
class SafariExtensionViewController: SFSafariExtensionViewController {
#IBOutlet weak var passwordMessage: NSTextField!
#IBOutlet weak var emailMessage: NSTextField!
#IBOutlet weak var message: NSTextField!
#IBOutlet weak var email: NSTextField!
#IBOutlet weak var password: NSSecureTextField!
static let shared = SafariExtensionViewController()
override func viewDidLoad() {
self.preferredContentSize = NSSize(width: 300, height: 250)
message.stringValue = ""
emailMessage.stringValue = ""
passwordMessage.stringValue = ""
}
override func viewDidAppear() {
if let storedEmail = UserDefaults.standard.object(forKey: "email") as? String {
if let stepView = Bundle.mainBundle.loadNibNamed(NSNib.Name(rawValue: "ExtensionStepsViewController"), owner: nil, topLevelObjects: nil)[0] {
self.view.addSubview(stepView)
}
}
}
#IBAction func userLogin(_ sender: Any) {
let providedEmailAddress = email.stringValue
let providedPassword = password.stringValue
let isEmailAddressValid = isValidEmailAddress(emailAddressString: providedEmailAddress)
self.message.stringValue = ""
emailMessage.stringValue = ""
passwordMessage.stringValue = ""
if isEmailAddressValid && providedPassword.count > 0 {
/* login process is handled here and store the email in local storage /*
/* TODO for now email is not stored in browser localstorage which has to be fixed */
let controller = "ExtensionStepsViewController"
let subview = ExtensionStepsViewController(nibName: NSNib.Name(rawValue: controller), bundle: nil)
self.view.addSubview(subview.view)
}
}
}
This way i get error like Type Bool has no subscript members my file structure looks something like this.
SafariExtensionViewController.xib (main one which is shown initially
with login screen)
SafariExtensionViewController.swift
ExtensionStepsViewController.xib(this view should be shown when user
is logged in instead of login screen)
ExtensionStepsViewController.swift
I am using xcode 10, swift 4, everything new.
UPDATE
I used the following block both in viewDidAppear(if there is email in localstorage then show extension steps view instead of login screen) and inside login function when the login is success but it does not navigate to that ExtensionStepsView
let controller = "ExtensionStepsViewController"
let subview = ExtensionStepsViewController(nibName: NSNib.Name(rawValue: controller), bundle: nil)
self.view.addSubview(subview.view)
Use case is show login at initial but if user is logged in then show another view but issue is now the view are merged
You got the error "Type Bool has no subscript members" because loadNibNamed(_:owner:topLevelObjects:) method of Bundle returns Bool struct that has no subscript members so you can't write like
true[0]
How to use this method correctly see the link and example from there:
var topLevelObjects : NSArray?
if Bundle.main.loadNibNamed(NSNib.Name(rawValue: "ExtensionStepsViewController"), owner: self, topLevelObjects: &topLevelObjects) {
let topLevelObjects!.first(where: { $0 is NSView }) as? NSView
}
Views were merged because you didn't remove previous views from the superview and added view from ExtensionStepsViewController to the same superview.
You can do the following steps to complete your issue:
Make SafariExtensionViewController inherited from SFSafariExtensionViewController that will be container (and parent) for two child view controllers such as LoginViewController and ExtensionStepsViewController and will be used to navigate between ones.
Make separately LoginViewController and ExtensionStepsViewController (both inherited from simple NSViewController) and its xibs.
Right after user logins transit from LoginViewController to ExtensionStepsViewController
As an example but instead of ParentViewController you have to use your implementation SafariExtensionViewController as I explain above in the first step.
public protocol LoginViewControllerDelegate: class {
func loginViewControllerDidLoginSuccessful(_ loginVC: LoginViewController)
}
public class LoginViewController: NSViewController {
weak var delegate: LoginViewControllerDelegate?
#IBAction func login(_ sender: Any) {
// login logic
let isLoginSuccessful = true
if isLoginSuccessful {
self.delegate?.loginViewControllerDidLoginSuccessful(self)
}
}
}
public class ExtensionStepsViewController: NSViewController {
}
public class ParentViewController: NSViewController, LoginViewControllerDelegate {
weak var login: LoginViewController! // using of force unwrap is anti-pattern. consider other solutions
weak var steps: ExtensionStepsViewController!
public override func viewDidLoad() {
let login = LoginViewController(nibName: NSNib.Name(rawValue: "LoginViewController"), bundle: nil)
login.delegate = self
// change login view frame if needed
login.view.frame = self.view.frame
self.view.addSubview(login.view)
// instead of setting login view frame you can add appropriate layout constraints
self.addChildViewController(login)
self.login = login
let steps = ExtensionStepsViewController(nibName: NSNib.Name(rawValue: "ExtensionStepsViewController"), bundle: nil)
steps.view.frame = self.view.frame
self.addChildViewController(steps)
self.steps = steps
}
// MARK: - LoginViewControllerDelegate
public func loginViewControllerDidLoginSuccessful(_ loginVC: LoginViewController) {
self.transition(from: self.login, to: self.steps, options: .slideLeft) {
// completion handler logic
print("transition is done successfully")
}
}
}
Here is a swift playground with this example.
UPD:
You can instantiate NSViewController in several ways:
Use NSStoryboard that allows to load view of NSViewController from .storyboard file:
let storyboard = NSStoryboard(name: NSStoryboard.Name("NameOfStoryboard"), bundle: nil)
let viewController = storyboard.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier("NSViewControllerIdentifierInStoryboard"))
Use appropriate initialiser of NSViewController to load view of it from .xib file:
let steps = ExtensionStepsViewController(nibName: NSNib.Name(rawValue: "ExtensionStepsViewController"), bundle: nil)
Use default initialiser but you have to load view directly by overriding loadView() method if name of xib file is different from name of view controller class:
let steps = ExtensionStepsViewController()
// Also you have to override loadView() method of ExtensionStepsViewController.

Why is my prepareForSegue code activating the wrong button?

I'm learning how to program and am playing with a Swift project in Xcode. The main storyboard has two view controllers. The first view controller is simply called ViewController and the second view controller is called HelpScreenViewController.
In ViewController I have a "help" button that switches the user to HelpScreenViewController. This button uses a segue called "goToHelpScreenSegue".
In HelpScreenViewController I have three buttons:
"Close" button to dismisses the view (no segue used)
"Send Feedback" button to generate a new email in the Mail app (no segue used)
"Reset Game" button to call a function that is coded within the first ViewController. This third button uses a segue called "resetGameSegue".
What I'm trying to do is...
...Get the "Reset Game" button on the HelpScreenViewController to reset the game by calling a function that's coded within the first view controller.*
To try and get this to work the way I want, I've used the following code:
WITHIN first main ViewController
import UIKit
import iAd
import AdSupport
import AVFoundation //audio
import GameplayKit
class ViewController: UIViewController, ADBannerViewDelegate, MyResetGameProtocol {
#IBOutlet weak var Banner: ADBannerView!
#IBOutlet weak var buttonA: UIButton!
#IBOutlet weak var buttonB: UIButton!
#IBOutlet weak var buttonC: UIButton!
#IBOutlet weak var buttonD: UIButton!
#IBOutlet weak var labelQuestion: UILabel!
#IBOutlet weak var labelScore: UILabel!
#IBOutlet weak var labelTotalQuestionsAsked: UILabel!
#IBOutlet weak var labelFeedback: UILabel!
#IBOutlet weak var buttonNext: UIButton!
var score :Int! = 0
var totalquestionsasked :Int! = 0
var allEntries : NSArray!
var shuffledQuestions: [AnyObject]!
var nextQuestion = -1
var currentCorrectAnswerIndex : Int = 0
var audioPlayer = AVAudioPlayer()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.Banner?.delegate = self
self.Banner?.hidden = true
LoadAllQuestionsAndAnswers()
if #available(iOS 9.0, *) {
shuffledQuestions = GKRandomSource.sharedRandom().arrayByShufflingObjectsInArray(allEntries as [AnyObject])
nextQuestion++
LoadQuestion(nextQuestion)
// Fallback on earlier versions
}else{
let randomNumber = Int(arc4random_uniform(UInt32(allEntries.count)))
LoadQuestionPreiOS9(randomNumber)
}
LoadScore()
AdjustInterface()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let viewController = segue.destinationViewController as! HelpScreenViewController
viewController.controller = self
}
func ResetGame() {
PlaySoundReset()
score = 0
totalquestionsasked = 0
SaveScore()
LoadScore()
}
func PlaySoundReset()
{
let alertSound = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("pcbeep", ofType: "wav")!)
do {
audioPlayer = try AVAudioPlayer(contentsOfURL: alertSound)
} catch {
}
audioPlayer.prepareToPlay()
audioPlayer.play()
}
func SaveScore()
{
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setInteger(score, forKey: "Score")
defaults.setInteger(totalquestionsasked, forKey: "Out of")
}
func LoadScore()
{
let defaults = NSUserDefaults.standardUserDefaults()
score = defaults.integerForKey("Score")
totalquestionsasked = defaults.integerForKey("Out of")
labelScore.text = "Score: \(score)"
labelTotalQuestionsAsked.text = "out of \(totalquestionsasked)"
}
and so on....
WITHIN the second HelpScreenViewController
import UIKit
protocol MyResetGameProtocol {
func ResetGame()
}
class HelpScreenViewController: UIViewController, MyResetGameProtocol {
var controller: MyResetGameProtocol? // reference to the delegate alias First Controller
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
#IBAction func SendFeedback(sender: AnyObject) {
UIApplication.sharedApplication().openURL(NSURL(string: "mailto:feedback#felice.ws?")!)
}
#IBAction func DismissView(sender: AnyObject) {
self.dismissViewControllerAnimated(true, completion: nil) }
#IBAction func buttonResetGame(sender: AnyObject) {
controller.ResetGame()
}
}
Now, at the moment with the above code what happens is that if the user taps the "help" button in the first main ViewController (i.e. goToHelpScreenSegue), not only does it take the user to the help screen, but it also calls the function I want activated when the user taps on the "Reset Game" button instead. That is, at the moment, it's the "help" button that resets the game before taking the user to the help screen.
Now, within the help screen, the first two buttons work normally (but they're not using segues). Tapping on the third button (the Reset Game one) simply returns the user back to the main screen. It doesn't call the function, doesn't reset the game.
I've lost count of the times I've changed the code around to try and get it to work right, but I've obviously missed something really obvious.
In particular, I've tried using the following code instead within the main ViewController:
override func prepareForSegue(segue: UIStoryboardSegue?, sender: AnyObject?) {
if segue?.identifier == "resetGameSegue" {
let viewController = segue!.destinationViewController as! HelpScreenViewController
viewController.controller = self
}
However, this results in nothing happening. What I mean is that the button on the main screen works properly (taking the user to the help screen and not incorrectly calling the resetGame function). And, within the help screen the first two buttons work as expected, but the "Reset Game" button just returns the user to the first screen but without calling the ResetGame function.
I also tried removing the IBActions from both my code and the connections inspector for the "Reset Game" button, but that made no difference either.
Any assistance would be most appreciated as I'm just not getting it! :(
I'm agree with MikeG, that you should probably learn about how delegates should be implemented. But the thing you're doing wrong inside this code is that you're not actually calling ResetGame() function on your delegate. Try to implement your #IBAction function in this way:
#IBAction func buttonResetGame(sender: AnyObject) {
controller?.ResetGame()
}
And yeah, if I understand your logic correctly your HelpScreenViewController should not implement MyResetGameProtocol cause your ViewController is the one who's implementing it.

UISlider, save status

My question is about the UISlider. I managed to implement everything but i don't know how i can save its status.
Ive looked everywhere but al the posts are in older versions of swift/xcode. So the question is how do i save its status so that when i go to another view and then come back the status is still the same.
Thanks very much!
import UIKit
class SettingsViewController: UIViewController {
var sequeInt = 0
let savedWordLength = NSUserDefaults.standardUserDefaults()
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBOutlet weak var wordLength: UISlider!
#IBOutlet weak var wordLengthValue: UILabel!
var selectedValue: Int = 5
#IBAction func valueChanged(sender: UISlider) {
selectedValue = Int(sender.value)
savedWordLength.setInteger(selectedValue, forKey: "myInt")
let ourInt = savedWordLength.integerForKey("myInt")
sequeInt = ourInt
print (sequeInt)
wordLengthValue.text = String(ourInt)
}
UISlider value property is a Float so you can use NSUserDefault's method setFloat to save its value and retrieve it next time your view appears using NSUserDefaults method floatForKey.
to save it:
NSUserDefaults.standardUserDefaults().setFloat(sender.value, forKey: "wordLength")
load it:
override func viewWillAppear(animated: Bool) {
wordLength.setValue(NSUserDefaults.standardUserDefaults().floatForKey("wordLength"), animated: false)
}
Follow these steps.
In your view will appear.
fontSlider.setValue(UserDefaults.standard.float(forKey: "slider_value"), animated: false)
Take another outlet from storyBoard as "editingDidEnd".
In that function:
UserDefaults.standard.set(fontSlider.value, forKey: "slider_value")
And finally in your ValueChanged Outlet.
UserDefaults.standard.set(fontSlider.value, forKey: "slider_value")

swift - Call a class function in viewController

hi im new to SO so i hope i make everything right.... :)
i started some Days ago iOS programming and no i have a problem that drives me crazy!
Here is the code of the class FactBook:
import Foundation
import UIKit
public class FactBook {
var randomNumberForAll: Int!
let factsArray = [
"Ants stretch when they wake up in the morning.",
"Ostriches can run faster than horses.",
"Olympic gold medals are actually made mostly of silver.",
"You are born with 300 bones; by the time you are an adult you will have 206.",
"It takes about 8 minutes for light from the Sun to reach Earth.",
"Some bamboo plants can grow almost a meter in just one day.",
"The state of Florida is bigger than England.",
"Some penguins can leap 2-3 meters out of the water.",
"On average, it takes 66 days to form a new habit.",
"Mammoths still walked the earth when the Great Pyramid was being built.",
"You can finish the entire FunFacts iOS app course in the time it takes to set up the emulator for the Android course"
]
let imagesArray = [
UIImage(named: "ants.jpg"),
UIImage(named: "ostriches.jpg"),
UIImage(named: "olymp.jpg"),
UIImage(named: "bones.jpg"),
UIImage(named: "light.jpg"),
UIImage(named: "bamboo.jpg"),
UIImage(named: "florida.jpg"),
UIImage(named: "penguins.jpg"),
UIImage(named: "habit.jpg"),
UIImage(named: "mammoth.jpg")
]
func randomFact() ->String {
//Count
var arrayCount = UInt32(factsArray.count)
//Random Number from count
var unsignedRandomNumber = arc4random_uniform(arrayCount)
//Random Number as Int
var randomNumber = Int(unsignedRandomNumber)
self.randomNumberForAll = randomNumber
return factsArray[randomNumber]
}
func randomImage() -> UIImage {
var imageRandom = randomNumberForAll
return imagesArray[imageRandom]!
}
}
Here is the ViewController:
import UIKit
class ViewController: UIViewController {
//Lable, Structs etc.----------------------------------NEU----------------------------
#IBOutlet weak var funFactLable: UILabel!
#IBOutlet weak var funFactButton: UIButton!
#IBOutlet weak var imageView: UIImageView!
let colorWheel = ColorWheel()
var counter = 0
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
//Loads first Label Text
funFactLable.text = "An interestig Fun Fact comes with one push!"
funFactButton.setTitle("For the first Fun Fact - Push!", forState: UIControlState.Normal)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//ACTIONS-------------------------------------------------------------------------------------
#IBAction func showFunFact() {
var randomColor = colorWheel.randomColor()
var randomImage = FactBook.randomImage()
var randomFact = FactBook.randomFact()
counter++
//BackgroundColor change
view.backgroundColor = randomColor
//Button-TextColor change
funFactButton.tintColor = randomColor
//Button-Title = Counter + Text
funFactButton.setTitle("\(counter). Fun Fact", forState: UIControlState.Normal)
//fadeIn fadeOut FactLable
self.funFactLable.fadeOut(completion: {
(finished: Bool) -> Void in
self.funFactLable.text = randomFact
self.funFactLable.fadeIn()
})
//fadeIn fadeOut ImageView
self.imageView.fadeOut(completion: {
(finished: Bool) -> Void in
self.imageView.image = randomImage
self.imageView.fadeIn()
})
}
}
so the problem is, i cant call the functions (randomFact and randomImage) in the ViewController.
But always the Error Missing argument for parameter #1 in call comes up.
When i change the class factbook to struct i can call the funcĀ“s but then the self.randomNumberForAll doesnt work.
What i just want is to use the randomnumber from the func randomFact() in the func randomImage()....
Thank you if u can help me :) !!!!
I hope this isn't a case of the blind trying to lead the blind as I'm new to swift, but I took this course too recently and was playing around with the code similarly to you. Seems like loading in the Factbook like you did Colorwheel should eliminate your missing parameter error. Unlike the colorwheel though, maybe it has to be a variable instead of a constant, so that you can store and change your randomFactForAll:
let colorWheel = ColorWheel()
var factBook = FactBook()
little late, hope this helps
Need to add keyword "class" to your functions randomFact() and randomImage() to make them as class functions.
Please check the following question for similar issue.