For a given simple audio app with a few buttons:
The button references inside ViewController is:
#IBOutlet weak var recordAudioButton: UIButton!
#IBOutlet weak var playAudioButton: UIButton!
#IBOutlet weak var processAudioButton: UIButton!
But where are those button names and references inside the xcode gui? Notice below that the Allow Recording button is highlighted: but there is no mention of recordAudioButton as a button name:
I want to modify the enabling/disabling logic of a different button that does not have a reference yet.. but can not see how/where to do that . The dialog does not show a way to view/change the button references. So where is the place to do that?
See in Referencing Outlets Section for each button.
You can set disable after buttons setup
#IBOutlet weak var recordAudioButton: UIButton! {
didSet { recordAudioButton.isEnabled = false }
}
#IBOutlet weak var playAudioButton: UIButton! {
didSet { playAudioButton.isEnabled = false }
}
#IBOutlet weak var processAudioButton: UIButton! {
didSet { processAudioButton.isEnabled = false }
}
Then in viewDidLoad check for permission
AVAudioSession.sharedInstance().requestRecordPermission() { [unowned self] allowed in
DispatchQueue.main.async {
self.recordAudioButton.isEnabled = allowed
self.playAudioButton.isEnabled = allowed
self.processAudioButton.isEnabled = allowed
}
}
Then your code
#IBAction func askForPermissions() {
recordingSession = AVAudioSession.sharedInstance()
do {
try recordingSession.setCategory(.playAndRecord, mode: .default)
try recordingSession.setActive(true)
recordingSession.requestRecordPermission() { [unowned self] allowed in
// UI related work has to be executed on main thread(queue)
DispatchQueue.main.async {
self.recordAudioButton.isEnabled = allowed
self.playAudioButton.isEnabled = allowed
self.processAudioButton.isEnabled = allowed
}
}
} catch let error {
presentError(withMessage: error.localizedDescription)
}
}
You just defined the button as an outlet. So it does not appear on the Touch Up Inside, it appears at outlets area. But you connect your other button to an action function, this button appears on the Touch Up Inside.
Given the starting point / hint from #Picode here is what I was missing to get a new UIButton reference. A Medium article helped pave the way https://medium.com/#GanChau/outlet-vs-action-connections-in-xcode-b5331fb233a1 . In particular we need to have both an Editor and the Visual Designer showing:
So on my project now I control-clicked on the new button Run DSP and the context menu shows up:
Now select New Referencing Outlet and connect it to the ViewController code:
I typed in dspJsButton for the Name and we get the following code generated:
#IBOutlet weak var dspJsButton: UIButton!
Related
The use case of the app I am developing is I will have login view at the initial. When user logs in with valid credentials, the user should see another view saying welcome user. I am totally beginner and I don't know much more about xcode. I see the screen navigation from storyboard but I have already done many things in xib.
Here is what I have done
SafariExtensionViewController.swift
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 = ""
}
#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 {
// api call is done here
// when success should show another screen
} else {
emailMessage.textColor = NSColor.red
emailMessage.stringValue = "Invalid Email"
}
}
}
here is the screenshot of xib.
Technology used
swift 4
xcode 9
not IOS its mainly for app extension
UPDATE
I am not using storyboard and also it's not IOS. I am using xib and from macos project I am trying to develop app extension which will be shown in browser as an extension.
A lot of time left from question posted, but it can be helpful for others as me (I'm porting safari legacy extension to safari app extension) and find the way with use of NSTabView with tabless style:
The use is:
Ensure to add NSObject in your storyboard from the Library:
And connect with the tabview from Outlet:
I'm rather newbie in Cocoa and Swift and if anyone knows more beautiful solution for routing, please share it with others!
This question already has answers here:
(NSMenuItem): missing setter or instance variable
(3 answers)
Closed 4 years ago.
Tutorial for Hello World
I tried using the tutorial, link described above which was going until the execution but when i use the button click to display the name it show some error
Failed to connect (sayButtonClicked) outlet from
(HelloWorld.ViewController) to (NSButton): missing setter or instance
variable
import Cocoa
class ViewController: NSViewController {
#IBOutlet weak var nameField: NSTextField!
#IBOutlet weak var helloLabel: NSTextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
#IBAction func sayButtonClicked(_ sender: Any) {
var name = nameField.stringValue
if name.isEmpty{
name = "World"
}
let greeting = "Hello\(name)!"
helloLabel.stringValue = greeting
}
}
It sounds like you have an outlet connection in your storyboard named "sayButtonClicked" but "sayButtonClicked" is an IBAction, not an outlet. Try doing the following:
Delete that "sayButtonClicked" outlet from your storyboard.
Open your storyboard in the editor and the source-code for the view controller in an "assistant editor"
Control-drag from the dot next to your IBAction in your code onto the button in your storyboard. This will connect the action to the button. You may need to select "touch up inside" as the event you want to trigger the action.
I have a PDFView and a PDFThumbnailView and implemented it this way:
class PDFViewController: NSViewController {
#IBOutlet weak var pdfView: PDFView!
#IBOutlet weak var pdfThumbnailView: PDFThumbnailView!
override func viewDidLoad() {
super.viewDidLoad()
// Do view setup here.
let doc = PDFDocument(data: NSData(contentsOfFile: "file.pdf")!)
pdfView.setDocument(doc)
pdfView.setAllowsDragging(true)
pdfThumbnailView.setPDFView(pdfView)
pdfThumbnailView.setAllowsDragging(true)
}
}
Since the documentation says:
Sets whether users can drag thumbnails within the thumbnail view; that
is, re-order pages in the document.
I thought this would do it, but it isn't doing anything. I can't drag and drop and so reorder the document.
Connect pdfThumbnailView and pdfView before setting the document, in the xib or in code.
I need to catch the modification of a switch in a dynamic cell.
The app has dynamic cells to list all BLE devices which where found.
The BLE device should be able to turn on/off via switch.
Now is the problem, I can't catch the switch via Outlet or Action.
How is it possible to catch a change from a dynamic cell.
UI for the problem looks like that:
UI with dynamic cell
I found the point where I can catch the tap but there I can't use my methods because in a class type UITableViewCell CoreBluetooth is not supported and I can't fill out the attribute for the CoreBluetooth methods.
import UIKit
class remoteCellTableViewCell: UITableViewCell{
//MARK: Properties
#IBOutlet weak var remoteCellLabel: UILabel!
#IBOutlet weak var remoteCellImageView: UIImageView!
#IBOutlet weak var remoteCellSwitch: UISwitch!
#IBOutlet weak var remoteCellPower: UIProgressView!
override func awakeFromNib() {
super.awakeFromNib()
}
//HERE I CAN CATCH THE SWITCH TAP BUT I CAN'T USE CoreBluetooh IN THIS CLASS
#IBAction func onOff(sender: AnyObject) {
//OBJECT FROM THE CLASS FOR CONNECT AND SEND TO THE PERIPHERAL
var connection: ViewController = ViewController()
connection.viewDidLoad()
//CANT FILLOUT THE ATTRIBUTES BECAUSE OF MISSING COREBLUETOOTH SUPPORT
//-->
connection.centralManagerDidUpdateState(<#T##central: CBCentralManager##CBCentralManager#>)
connection.centralManager(<#T##central: CBCentralManager##CBCentralManager#>, didDiscoverPeripheral: <#T##CBPeripheral#>, advertisementData: <#T##[String : AnyObject]#>, RSSI: <#T##NSNumber#>)
connection.centralManager(<#T##central: CBCentralManager##CBCentralManager#>, didConnectPeripheral: <#T##CBPeripheral#>)
connection.centralManager(<#T##central: CBCentralManager##CBCentralManager#>, didDiscoverPeripheral: <#T##CBPeripheral#>, advertisementData: <#T##[String : AnyObject]#>, RSSI: <#T##NSNumber#>)
connection.centralManager(<#T##central: CBCentralManager##CBCentralManager#>, didConnectPeripheral: <#T##CBPeripheral#>)
connection.peripheral(<#T##peripheral: CBPeripheral##CBPeripheral#>, didDiscoverServices: <#T##NSError?#>)
connection.peripheral(<#T##peripheral: CBPeripheral##CBPeripheral#>, didDiscoverCharacteristicsForService: <#T##CBService#>, error: <#T##NSError?#>)
connection.peripheral(<#T##peripheral: CBPeripheral##CBPeripheral#>, didUpdateValueForCharacteristic: <#T##CBCharacteristic#>, error: <#T##NSError?#>)
connection.peripheral(<#T##peripheral: CBPeripheral##CBPeripheral#>, didWriteValueForDescriptor: <#T##CBDescriptor#>, error: <#T##NSError?#>)
//->
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
Use Tags to get the switch state. here is the code that i used to get the button click action. Like this
In your cellForRowAtIndexPath assign tag to the button.
cell.absentButton.tag = indexPath.row
In your button action get the row of the button
if let button = sender as? UIButton {
if button.selected {
// set selected
let row = sender.tag
}
}
From this you can get which switch is changed.
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.