Why isn't this variable showing in Objective-C? [duplicate] - xcode

I'm working on converting my project from Objective-c to Swift, and a Swift class I'm using, I have a protocol I'm trying to access in an Objective-c class. My problem is, the delegate is not accessible in the objective-c class. Here is my swift class:
protocol RateButtonDelegate {
func rateButtonPressed(rating: Int)
}
class RateButtonView: UIView {
var delegate: RateButtonDelegate?
var divider1: UIView!
var divider2: UIView!
}
When I look at the MyProject-Swift.h file, I don't see the delegate:
#interface RateButtonViewTest : UIView
#property (nonatomic) UIView * divider1;
#property (nonatomic) UIView * divider2;
#end
and when I try to use rateButtonView.delegate in my Objective-c class, I get a compiler error.
Anyone know the issue? How do access a Swift protocol in Objective-c?

You need to mark your protocol with the #objc attribute for it to be accessible from Objective-C:
#objc protocol RateButtonDelegate {
func rateButtonPressed(rating: Int)
}
This page from Apple's documentation covers the issue.

Related

Drag - connect an UISwitch to an IBOutlet on a delegate class

My goal is to enable/disable the editing of a UITextField with a UISwitch using delegates. This is the delegate class:
import Foundation
import UIKit
class SwitchedTextFieldDelegate : NSObject, UITextFieldDelegate{
#IBOutlet weak var switchText : UISwitch!
func textFieldShouldBeginEditing(textField: UITextField) -> Bool {
//Here I intended to read the UISwitch state
print("Can't touch this")
return false
}
}
I've tried to drag-connect the IBOutlet to the storyboard, but it is not possible. I can do it on the main view controller, which inherits UIViewController. I've already learned that multiple inheritance is not possible in Swift. How would you solve this? I'll try using an IBAction instead.
In your main view controller drag IBOutlet of a UITextField and UISwitch. Then confirm the UITextField Delegate. Now implement the UITextField Delegate method Like this:
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
if switchText.on{
return true
}else{
return false
}
}
For better understanding I have shared my ViewController screen shot.Here FirstViewController is just like your MainViewController. Hope this will help you.

Ask NSSlider if the user still has the mouse button pressed? (swift)

Hi I'm implementing a subclass of NSSlider and NSSliderCell in swift, I would like to check/retrieve the _scFlags.isPressed property from NSSliderCell, I found that there is a 'hack' in Objective-C to do it when calling from another class (which is not really needed if you subclass NSSlider in Objective-C):
http://www.cocoabuilder.com/archive/cocoa/54913-nsslider.html
However, in swift, when I search in the API (AppKit -> NSSliderCell), I can find a struct which I suppose is the one I need, and nothing else but the init() inside:
public struct __sliderCellFlags {
public init()
}
and I can't even call it from the subclass. All these show as error:
self.__sliderCellFlags
self._scFlags
super.__sliderCellFlags
super._scFlags
Am I missing something? Is there a different way to call these properties?
Use Objective-C to implement a category on NSSliderCell which has a property to access the struct data and use the property from Swift.
NSSlider+FlagsAccessor.h
#interface NSSlider (FlagsAccessor)
#property (nonatomic, readonly) BOOL isPressed;
#end
NSSlider+FlagsAccessor.m
#import "NSSlider+FlagsAccessor.h"
#interface NSSliderCell (FlagsAccessor)
#property (nonatomic, readonly) BOOL isPressed;
#end
#implementation NSSlider (FlagsAccessor)
- (BOOL)isPressed
{
NSSliderCell *cell = self.cell;
return cell.isPressed;
}
#end
#implementation NSSliderCell (FlagsAccessor)
- (BOOL)isPressed
{
return self->_scFlags.isPressed == 1;
}
#end
Then to use It from Swift just call self.isPressed. Here's a sample project.
Don't forget to import your category header in your bridging header (Xcode will prompt you to create a bridging header when you add Objective-C code to a Swift project).

Access an IBOutlet from another class in Swift

I'm new to Swift and Mac App.
So I'm writing an Mac App today and I still confuse how to access an IBOutlet from another class after searching a lot.
I'm using StoryBoard and there are two NSTextField path mirror in my ViewController.
I have created a custom class Path.swift for the first NSTextField path to know when the text in path has changed.
class Path: NSTextField, NSTextFieldDelegate
{
override func drawRect(dirtyRect: NSRect)
{
super.drawRect(dirtyRect)
// Drawing code here.
self.delegate = self
}
var current = ""
override func controlTextDidChange(obj: NSNotification)
{
current = self.stringValue
println("Current is \(current)")
}
}
And there are two outlets defined in ViewController.swift
class ViewController: NSViewController
{
override func viewDidLoad()
{
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override var representedObject: AnyObject? {
didSet {
// Update the view, if already loaded.
}
}
#IBOutlet weak var path: NSTextField!
#IBOutlet weak var mirror: NSTextField!
}
And when user type something in the first NSTextField path, I want the second NSTextField mirror shows the same string as path.
I tried to use ViewController().mirror.stringValue = current, but I got fatal error: unexpectedly found nil while unwrapping an Optional value
After googling a lot, I knew that I have created a new instance of ViewController instead of accessing the current existing instance of ViewController.
So my question is how I can access the IBOutlet in ViewController.swift from Path.swift class (how to access the current existing instance of ViewController).
Any help will be greatly appreciated.
Thanks in advance.

How do you use Interface builder with Swift?

When hooking Swift code up to a Storyboard, how do you add the IBAction and IBOutlet tags?
Add IBAction and IBOutlet attributes to variables and functions so they can be visible in Interface builder.
class ViewController: UIViewController {
#IBOutlet var label: UILabel?
#IBAction func doTap(x:UIButton) {
println("Tapped: \(x)")
}
}
Below code shows IBOutlet and IBAction format in Swift :
class MyViewController: UIViewController {
#IBOutlet weak var btnSomeButton: UIButton?
#IBOutlet weak var lblLabelItem: UILabel?
#IBAction func btnSomeButtonClicked(sender: UIButton) {
...
}
}
You can bind them same way as done in Objective-C.
Just use old ctrl + drag technique which was popular in Xcode5 and everything works fine.
I would agree more with Jayprakash than the upvoted first answer. The only thing I would correct is the marking of the IBOutlets as implicitly unwrapped with the ! The first answer used to be correct, but several changes were made in Swift and how it interacts with IB in the latest release. In Swift, IBOutlets no longer have any implicit behavior or magic--they are simply annotations for IB. As of the date of this response, the following code is correct:
// How to specify an the equivalent of IBOutletCollection in Swift
#IBOutlet var fields: [UITextField]!
// How to specify a standard IBOutlet
#IBOutlet weak var button: UIButton!
// How to specify an IBAction
#IBAction func buttonWasPressed(sender: UIButton) { ... }
While creating a project, you should have selected the storyboard, so that you can add your IBOutlet's directly in the story board.
The Below code gives you a idea of how to add IBOutlet to the UILabel
class ViewController: UIViewController {
#IBOutlet var label : UILabel
}

Text change notification for an NSTextField

I would like to use the code from the answer to this question: How to observe the value of an NSTextField on an NSTextField in order to observe changes on the string stored in the NSTextField.
[[NSNotificationCenter defaultCenter]
addObserverForName:NSTextViewDidChangeSelectionNotification
object:self.textView
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification *note){
NSLog(#"Text: %#", self.textView.textStorage.string);
}];
The class used here is an NSTextView. I can't find a notification in NSTextField to use instead of NSTextViewDidChangeSelectionNotification.
Is there a notification available in NSTextField that can be used in this case ?
If you just want to detect when the value of a text field has changed, you can use the controlTextDidChange: delegate method that NSTextField inherits from NSControl.
Just connect the delegate outlet of the NSTextField in the nib file to your controller class, and implement something like this:
- (void)controlTextDidChange:(NSNotification *)notification {
NSTextField *textField = [notification object];
NSLog(#"controlTextDidChange: stringValue == %#", [textField stringValue]);
}
If you're creating the NSTextField programmatically, you can use NSTextField's setDelegate: method after creation to specify the delegate:
NSTextField *textField = [[[NSTextField alloc] initWithFrame:someRect] autorelease];
[textField setDelegate:self]; // or whatever object you want
Delegation is one of the fundamental design patterns used throughout Cocoa. Briefly, it allows you to easily customize the behavior of standard objects (in this case, user interface objects) without the complexity involved in having to subclass the object to add that additional behavior. For example, another lower-level way to detect when the text in a textfield has changed might be to create your own custom NSTextField subclass in which you override the keyDown: method that NSTextField inherits from NSResponder. However, subclassing like that is difficult because it can require that you have an intimate knowledge of the object's inheritance hierarchy. For more info, definitely check out the following:
Cocoa Fundamentals Guide: Delegates and Data Sources
Regarding what id <NSTextFieldDelegate> means: it means a generic object (id) that declares itself as conforming to the <NSTextFieldDelegate> protocol. For more info on protocols, see The Objective-C Programming Language: Protocols.
Sample GitHub project at: https://github.com/NSGod/MDControlTextDidChange
Xcode 9.2. with Swift 4.0.3.
The NSTextField must be connected via interface builder for this implementation to work.
import Cocoa
#objc public class MyWindowController: NSWindowController, NSTextFieldDelegate {
#IBOutlet weak var myTextField: NSTextField!
// MARK: - ViewController lifecycle -
override public func windowDidLoad() {
super.windowDidLoad()
myTextField.delegate = self
}
// MARK: - NSTextFieldDelegate -
public override func controlTextDidChange(_ obj: Notification) {
// check the identifier to be sure you have the correct textfield if more are used
if let textField = obj.object as? NSTextField, self.myTextField.identifier == textField.identifier {
print("\n\nMy own textField = \(self.myTextField)\nNotification textfield = \(textField)")
print("\nChanged text = \(textField.stringValue)\n")
}
}
}
Console output:
My own textField = Optional(<myApp.NSTextField 0x103f1e720>)
Notification textfield = <myApp.NSTextField: 0x103f1e720>
Changed text = asdasdasddsada
You should use NSTextFieldDelegate and implement controlTextDidChange. Test in macOS 10.14 and Swift 4.2
import Cocoa
class ViewController: NSViewController, NSTextFieldDelegate {
#IBOutlet weak var textField: NSTextField!
override func viewDidLoad() {
super.viewDidLoad()
textField.delegate = self
}
func controlTextDidChange(_ obj: Notification) {
let textField = obj.object as! NSTextField
print(textField.stringValue)
}
}
I believe you want to read up on the field editor which is essentially a (hidden) NSTextView that handles the text input to all the NSTextFields in a given window. The section on "Using Delegation and Notification With the Field Editor" should point you in the right direction.
In Swift it's
public override func controlTextDidChange(_ obj: Notification) {
}

Resources