How do I set a view to allow vibrancy in swift.
I'm trying:
func allowsVibrancy() -> Bool {
return true
}
but getting an error:
Method 'allowsVibrancy()' with Objective-C selector 'allowsVibrancy' conflicts with getter for 'allowsVibrancy' from superclass 'NSView' with the same Objective-C selector
or even:
override func awakeFromNib() {
self.allowsVibrancy = true
println(self.allowsVibrancy)
}
I can do this in Onjective C with:
- (BOOL)allowsVibrancy {
return YES;
}
Any thoughts?
You should override property, not method
override var allowsVibrancy: Bool { return true }
Related
When directly assigning / implementing a Swift closure it is no problem to access class properties. But when I try to define the closure as class propertie as well, access to other class properties is not possible. Why is this?
Here is an example:
While the closure directly assigned to editorVC.completionBlock can access the class property tableView without any problem, the same code within leads to an error when the closure is defined as class property editorCompletionBlock:
class MyViewController: UIViewController {
#IBOutlet var tableView: UITableView!
func showEditor(withData: String) {
let editorVC = EditorViewController()
// Directly assign closure - Works without any problem
editorVC.completionBlock = { (result) in
self.tableView.reloadData()
doSomething(withResult: result)
// ...
}
present(editorVC, animated: true, completion: nil)
}
// Define closure as class property ==> Error
let editorCompletionBlock: EditorCompletionBlock = { (resut) in
// ERROR: Value of type '(MyViewController) -> () -> MyViewController' has no member 'tableView'
self.tableView.reloadData()
doSomething(withResult: result)
// ...
}
}
typealias EditorCompletionBlock = (String) -> Void
class EditorViewController: UIViewController {
var completionBlock: EditorCompletionBlock?
func closeEditor(withResult result: String) {
completionBlock?(result)
}
}
Reason:
You can't access self until the initialization process of a type is completed.
In your code, editorCompletionBlock is a stored property and you're trying to access self.tableView inside it. This is the reason it is giving compile time error.
Solution:
Instead, make editorCompletionBlock as a lazy property to get that working.
lazy var editorCompletionBlock: EditorCompletionBlock = { (result) in
self.tableView.reloadData()
doSomething(withResult: result)
}
Solution 1:
place your editorCompletionBlock in viewDidLoad(:_) and it should work like charm:
class MyViewController: UIViewController {
#IBOutlet var tableView: UITableView!
func showEditor(withData: String) {
let editorVC = EditorViewController()
editorVC.completionBlock = { (result) in
self.tableView.reloadData()
}
present(editorVC, animated: true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
let editorCompletionBlock: EditorCompletionBlock = { (resut) in
self.tableView.reloadData() ///should work :)
}
}
}
typealias EditorCompletionBlock = (String) -> Void
class EditorViewController: UIViewController {
var completionBlock: EditorCompletionBlock?
func closeEditor(withResult result: String) {
completionBlock?(result)
}
}
Solution 2:
Or you can just declare your closure as lazy:
lazy var editorCompletionBlock: EditorCompletionBlock = { (result)
in
self.tableView.reloadData()
doSomething(withResult: result)
}
I have a protocol
protocol Example: class {
var value: Bool { get set }
func foo()
func bar()
}
And extension:
extension Example {
// var value: Bool { // Error: Extensions must not contain stored properties
// didSet {
// switch value {
// case true:
// foo()
// case false:
// bar()
// }
// }
// }
func foo() {
// logic...
}
func bar() {
// logic...
}
}
When value is set to true, I want foo() to be called
When value is set to false, I want bar() to be called
However, I do not want to redundantly implement didSet{ } logic into every class that conforms to Example
But, if I try to add didSet{ } logic into the extension, Xcode says "Extensions must not contain stored properties".
What is the best practice for adding default property-observing logic without having to copy/paste into every conforming class?
The Goal:
I want any subclass of UIView to conform to my protocol Expandable. The requirements of my protocol are isExpanded: Bool, expand(), and collapse. I want isExpanded = true to call expand(), and isExpanded = false to call collapse() (much like the behavior of setting isHidden). But for every subclass of UIView, I don't want to have rewrite any logic. I'd like to just make the class conform to Expandable, and jump right in to setting isExpanded.
You don't need observers for what you're describing. You just need some storage for your state. Since you know this is an NSObject, you can do that with the ObjC runtime.
// Since we know it's a UIView, we can use the ObjC runtime to store stuff on it
private var expandedProperty = 0
// In Xcode 10b1, you can make Expandable require this, but it's probably
// nicer to still allow non-UIViews to conform.
extension Expandable where Self: UIView {
// We'll need a primitive form to prevent infinite loops. It'd be nice to make this private, but
// then it's not possible to access it in custom versions of expand()
var _isExpanded: Bool {
get {
// If it's not know, default to expanded
return objc_getAssociatedObject(self, &expandedProperty) as? Bool ?? true
}
set {
objc_setAssociatedObject(self, &expandedProperty, newValue, .OBJC_ASSOCIATION_ASSIGN)
}
}
var isExpanded: Bool {
get {
return _isExpanded
}
set {
_isExpanded = newValue
if newValue { expand() } else { collapse() }
}
}
func expand() {
_isExpanded = true // Bypassing the infinite loop
print("expand")
}
func collapse() {
_isExpanded = false
print("collapse")
}
}
If you didn't know that this were an NSObject, you can get the same thing with a global (private) dictionary that maps ObjectIdentifier -> Bool. It just leaks a tiny amount of memory (~16 bytes per view that you collapse).
That said, I wouldn't do it this way. Having two ways to do the same thing makes everything much more complicated. I would either have just isExpanded as settable, or have isExpanded as read-only and a expand and collapse. Then you don't need the extra _isExpanded.
You have to implement getter, setter explicitly:
protocol Example {
var value: Bool { get set }
func foo()
func bar()
}
extension Example {
var value: Bool {
get { return value }
set(newValue) {
value = newValue
value ? foo() : bar()
}
}
func foo() {
print("foo")
}
func bar() {
print("bar")
}
}
I'm working through a tutorial that uses NSSpeechSynthesizer and two of its NSSpeechSynthesizerDelegate protocol methods. In my ViewController, I don't explicitly call the protocol methods so I'm curious as to what do I need to research in order to understand how these methods are called during runtime? The delegate methods are working as expected but I'm wondering how are they being called which makes this possible?
import Cocoa
class MainWindowController: NSWindowController, NSSpeechSynthesizerDelegate, NSWindowDelegate {
//Now MainWindowController is more powerful by having its own KITT being able to delegate powerful functionality and do less work. The delegate will do all the heavy lifting and return the results to MainWindowController instances.
// MARK: - Properties
#IBOutlet weak var textField: NSTextField!
#IBOutlet weak var speakButton: NSButton!
#IBOutlet weak var stopButton: NSButton!
let speechSynth = NSSpeechSynthesizer.init(voice: NSSpeechSynthesizer.VoiceName.init(rawValue: "com.apple.speech.synthesis.voice.Victoria"))
var isSpeaking: Bool = false {
didSet {
updateButtons()
}
}
// MARK: - Overriden Properties
override var windowNibName: NSNib.Name? {
return NSNib.Name("MainWindowController")
}
// MARK: - Overidden Methods
override func windowDidLoad() {
super.windowDidLoad()
updateButtons()
speechSynth?.delegate = self
}
// MARK: - UI methods
#IBAction func speakIt(sender: NSButton) {
//Get tuype-in text as a string
let string = textField.stringValue
if string.isEmpty {
print("string from \(textField) is empty")
} else {
speechSynth?.startSpeaking(string)
isSpeaking = true
}
}
#IBAction func stopIt(sender: NSButton) {
speechSynth?.stopSpeaking()
}
func updateButtons(){
if isSpeaking {
speakButton.isEnabled = false
stopButton.isEnabled = true
} else {
speakButton.isEnabled = true
stopButton.isEnabled = false
}
}
// MARK: - NSSpeechSynthesizerDelegate Methods
//this functionality is considered more powerful and is made possible due to the speechSynthesizer.delegate = self
//the delegate is doing the work and reporting that completed work to the MainWindowController instance
//so kinda like the delegate is providing the signature and its up to us as the developers based on what we do with those parameters inside the function in order for us to add our own creativity.
func speechSynthesizer(_ sender: NSSpeechSynthesizer, didFinishSpeaking finishedSpeaking: Bool) {
//by setting this variable to FALSE, it will fire off the didSet computed property which this variable has both storage and behavior.
isSpeaking = false
}
// MARK: - NSWindowDelegate Methods
func windowShouldClose(_ sender: NSWindow) -> Bool {
return !isSpeaking
}
}
Your windowDidLoad method contains this line:
speechSynth?.delegate = self
This means the speech synthesizer object has a reference back to your MainWindowController, so the speech synthesizer object can send messages to your MainWindowController.
A simplified implementation inside NSSpeechSynthesizer could look something like this in Swift:
class NSSpeechSynthesizer: NSSoundDelegate {
weak var delegate: NSSpeechSynthesizerDelegate?
func startSpeaking(_ string: String) {
guard
let audioData = audioData(for: string),
let sound = NSSound(data: audioData)
else { return }
sound.delegate = self
sound.play()
}
// Part of NSSoundDelegate
func sound(_ sound: NSSound, didFinishPlaying finished: Bool) {
// The first ? means Swift only sends the message if
// delegate is not nil.
// The second ? means Swift only sends the message if delegate
// implements speechSynthesizer(_:didFinishSpeaking:).
delegate?.speechSynthesizer?(self, didFinishSpeaking: finished)
}
}
But it's actually implemented in Objective-C, where you have to be more verbose about checking whether the delegate handles the message:
- (void)sound:(NSSound *)sound didFinishPlaying:(BOOL)finished {
if ([delegate respondsToSelector:#selector(speechSynthesizer:didFinishSpeaking:)]) {
[delegate speechSynthesizer:self didFinishSpeaking:finished];
}
}
I am creating a custom subclass of UIControl (I need to override its draw method) and I want to add RxSwift to bind its isSelected property to my model.
So far so good. This works fine.
My problem is how can I do to change the value isSelected property in response of user touchUpInside event?.
My first try was to use the addTarget method of UIControl, but changing the value of isSelected programmatically is not reported by the ControlProperty (as stated in the doc). But I can figure another way to resolve this.
Any help appreciated.
Source code of the subclass:
class SYYesNoButton: UIControl {
override init(frame: CGRect) {
super.init(frame: frame)
// subscribe to touchUpInside event
addTarget(
self,
action: #selector(userDidTouchUpInside),
for: UIControlEvents.touchUpInside)
}
func userDidTouchUpInside() {
// change the value of the property
// this does not work,
// the change is not reported to the ControlProperty
// HOW CAN I CHANGE THIS ??
self.isSelected = !isSelected
}
}
Extensions to add reactive support:
extension SYYesNoButton {
var rx_isSelected: ControlProperty<Bool> {
return UIControl.valuePublic(
self,
getter: { (button) -> Bool in
return button.isSelected
},
setter: { (button, value) in
button.isSelected = value
})
}
}
extension UIControl {
static func valuePublic<T, ControlType: UIControl>(_ control: ControlType, getter: #escaping (ControlType) -> T, setter: #escaping (ControlType, T) -> ()) -> ControlProperty<T> {
let values: Observable<T> = Observable.deferred { [weak control] in
guard let existingSelf = control else {
return Observable.empty()
}
return (existingSelf as UIControl).rx.controlEvent([.allEditingEvents, .valueChanged])
.flatMap { _ in
return control.map { Observable.just(getter($0)) } ?? Observable.empty()
}
.startWith(getter(existingSelf))
}
return ControlProperty(values: values, valueSink: UIBindingObserver(UIElement: control) { control, value in
setter(control, value)
})
}
}
Thanks for all.
Once you have an actual UIControl, there's an even nicer way to a "native" RxCocoa extension called a ControlProperty using a helper method in RxCocoa.
For example:
extension Reactive where Base: someControl {
var someProperty: ControlProperty<Float> {
return controlProperty(editingEvents: .valueChanged,
getter: { $0.value },
setter: { $0.value = $1 })
}
}
This will expose the current value from the getter block whenever the specified UIControlEvent is fired, and will also set the value whenever some stream is bound to it.
It sort of acts like an Observable and Observer type together - you can observe its value, but can also subscribe to it.
If you are subclassing from UIControl, then you are making your own control class and you have to override one or more of beginTracking(_:with:), continueTracking(_:with:), endTracking(_:with:), or cancelTracking(with:) to make the control work the way you want. Then call sendActions(for:) with the correct event. The guts of a UIControl would not have Rx in it.
Taking a queue from UIButton, your control should not select itself, although it can highlight and unhighlight itself (when the user's finger is on it for example.)
Once you have properly created your UIControl, code outside the control can use Rx to observe it with no extra work on your part.
The following works (Updated for Swift 5/RxSwift 5):
class ViewController: UIViewController {
#IBOutlet weak var yesNoButton: SYYesNoButton!
private let bag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
yesNoButton.rx.controlEvent(.touchUpInside)
.scan(false) { v, _ in !v }
.bind(to: yesNoButton.rx.isSelected)
.disposed(by: bag)
}
}
#IBDesignable
class SYYesNoButton: UIControl {
override func layoutSubviews() {
super.layoutSubviews()
backgroundColor = isSelected ? .green : .red
}
override var isSelected: Bool {
didSet {
super.isSelected = isSelected
backgroundColor = isSelected ? .green : .red
}
}
}
How can we check if a parameter passed in a function is a value or a reference type? For example
func isReferenceType(toTest: Any) {
return true // or false
}
As we see here, we are not able to do this leveraging generics.
AnyObject is a protocol that any class type automatically conforms to, so you can write:
func isReferenceType(toTest: Any) -> Bool {
return toTest.dynamicType is AnyObject
}
class Foo { }
struct Bar { }
isReferenceType(Foo()) // true
isReferenceType(Bar()) // false
isReferenceType("foo") // false
isReferenceType(123) // false
isReferenceType([1,2,3]) // false
Swift 5
func isReferenceType(_ toTest: Any) -> Bool {
return type(of: toTest) is AnyClass
}