Swift 3: Convert PromiseKit deferred to RxSwift - swift3

I'm currently replacing PromiseKit with RxSwift, and need to convert my deferred promise to RxSwift.
Current implementation example in PromiseKit:
private var deferredDidLayout = Promise<()>.pending()
override func layoutSubviews() {
super.layoutSubviews()
self.deferredDidLayout.fulfill()
}
func setup() {
_ = self.didLayout().then {_ -> Void in
// Do my stuff only one time!
}
}
private func didLayout() -> Promise<()> {
return self.deferredDidLayout.promise
}
Current hack-implementation in RxSwift:
private let observableDidLayout = PublishSubject<Void>()
override func layoutSubviews() {
super.layoutSubviews()
self.observableDidLayout.onCompleted()
}
func setup() {
_ = self.observableDidLayout
.subscribe(onCompleted: { _ in
// Do my stuff only one time!
// Issue: Will be executed on every onCompleted() call
})
}
Thank you in regard!
PromiseKit: https://github.com/mxcl/PromiseKit
RxSwift: https://github.com/ReactiveX/RxSwift

I believe that 'Completable' is what you are looking for - https://github.com/ReactiveX/RxSwift/blob/master/Documentation/Traits.md#creating-a-completable

Related

UIImpactFeedbackGenerator is Not Working? UIKit - Xcode 13.4.1 - Swift 5

I want to generate vibration when I press the button but I get no results.
Helper class I created to manage vibrations:
import Foundation
import UIKit
final class HapticsManager{
static let shared = HapticsManager()
private init(){}
public func selectionVibrate(){
DispatchQueue.main.async {
let selectionImpactGenerator = UIImpactFeedbackGenerator()
selectionImpactGenerator.prepare()
selectionImpactGenerator.impactOccurred()
}
}
public func haptic(for type: UIImpactFeedbackGenerator.FeedbackStyle){
DispatchQueue.main.async {
let notificationGenerator = UIImpactFeedbackGenerator()
notificationGenerator.prepare()
notificationGenerator.impactOccurred()
}
}
}
in ViewDidLoad()
override func viewDidLoad() {
super.viewDidLoad()
HapticsManager.shared.selectionVibrate()
addTargets()
setStartGradientView()
showLayout()
}
Function of button with click target added:
#objc fileprivate func setButtonClicked(){
HapticsManager.shared.haptic(for: .heavy)
}
I tried many methods but no result.
Thanks...
There is no problem about your code but needs some additional information. You need to check if device hardware is support for CHHapticEngine like that;
public func haptic(for type: UIImpactFeedbackGenerator.FeedbackStyle) {
if CHHapticEngine.capabilitiesForHardware().supportsHaptics {
let notificationGenerator = UIImpactFeedbackGenerator()
notificationGenerator.prepare()
notificationGenerator.impactOccurred()
} else {
AudioServicesPlaySystemSound(1520)
}
}

Type 'Favorites.Type' cannot conform to 'Encodable'; only struct/enum/class types can conform to protocols

Please tell me what could be the problem with this error and how to fix it?
I'm use SwiftUI 2.0
"Type 'Favorites.Type' cannot conform to 'Encodable'; only struct/enum/class types can conform to protocols"
Code:
class Favorites: ObservableObject {
private var tasks: Set<String>
let defaults = UserDefaults.standard
init() {
let decoder = JSONDecoder()
if let data = defaults.value(forKey: "Favorites") as? Data {
let taskData = try? decoder.decode(Set<String>.self, from: data)
self.tasks = taskData ?? []
} else {
self.tasks = []
}
}
func getTaskIds() -> Set<String> {
return self.tasks
}
func isEmpty() -> Bool {
tasks.count < 1
}
func contains(_ task: dataTypeFont) -> Bool {
tasks.contains(task.id)
}
func add(_ task: dataTypeFont) {
objectWillChange.send()
tasks.insert(task.id)
save()
}
func remove(_ task: dataTypeFont) {
objectWillChange.send()
tasks.remove(task.id)
save()
}
func save() {
let encoder = JSONEncoder()
if let encoded = try? encoder.encode(Favorites) {
defaults.set(encoded, forKey: "Favorites")
}
}
}
Screenshot Error:
Error
Typo.
According to the load method you have to encode tasks not the class type
func save() {
let encoder = JSONEncoder()
if let encoded = try? encoder.encode(tasks) {
defaults.set(encoded, forKey: "Favorites")
}
}
And don't use value(forKey: with UserDefaults, there is a dedicated method
if let data = defaults.data(forKey: "Favorites") {

How to save variable in closure to external variable?

I'm trying to create a custom PickerView that gets it's data from an API call to a web-server. The problem I'm having is saving the parsed data into an external variable so that the PickerView protocol methods can access it.
// API Call / Parsing using Alamofire + Unbox
static func makeApiCall(completionHandler: #escaping (CustomDataStructure) -> ()) {
Alamofire.request(webserverUrl, method: .get).responseObject { (response: DataResponse<Experiment>) in
switch response.result {
case .success:
if var configParams = response.result.value {
let inputConfigs = removeExtrasParams(experiment: response.result.value!)
let modifiedViewModel = modifyViewModel(experiment: &configParams, inputConfigs: inputConfigs)
completionHandler(modifiedViewModel)
}
case .failure(_):
break
}
}
}
// Custom PickerClass
class CustomPickerView: UIPickerView {
fileprivate var customDS: CustomDataStructure?
override init() {
super.init()
dataSource = self
delegate = self
SomeClass.makeApiCall(completionHandler: { customds in
self.customDS = customds
})
}
...
}
extension CustomPickerView: UIPickerViewDelegate {
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
if let customds = customDS {
if let customDSValues = customds.inputs.first?.value {
return customDSValues[row]
}
}
return "apple"
}
}
extension CustomPickerView: UIPickerViewDataSource {
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
if let customds = customDS {
return customds.inputs.values.count
} else {
return 0
}
}
}
The problem I'm having is that customDS returns nil everytime.
What am I doing wrong here?
In the completion block of makeApiCall simply reload your pickerView's component on main thread and you all set to go.
SomeClass.makeApiCall(completionHandler: { customds in
self.customDS = customds
DispatchQueue.main.async {
self.reloadComponent(0)
}
})

Deletebackward() Swift 3

DeleteBackward() deletes only one character, is there any way to keep on deleting backwards ?
I am using emojiKeyboard and I have a delete emoticon. I detect the emoji being the delete emoticon and I call
if emoticon.isDelete{
deleteBackward()
return
}
Update:
Steven's solution works on buttons but not on my UITextView. Will try and find out why. I have tried having the addGestureRecognizer in ViewWillAppear as well as ViewDidLoad.
This should get you started, didn't test but should do the trick.
fileprivate var timer = Timer()
fileprivate var textField = UITextField() //change to your field
override func viewDidLoad() {
super.viewDidLoad()
let longPress = UILongPressGestureRecognizer(target: self, action: #selector(longPress(_:)))
textField.addGestureRecognizer(longPress)
}
func longPress(_ guesture: UILongPressGestureRecognizer) {
if guesture.state == UIGestureRecognizerState.began {
longPressBegun(guesture)
} else if guesture.state == UIGestureRecognizerState.changed {
//longPressStateChanged(guesture)
} else if guesture.state == UIGestureRecognizerState.ended {
longPressEnded()
} else if guesture.state == UIGestureRecognizerState.cancelled {
longPressCancelled()
}
}
func longPressBegun(_ guesture: UILongPressGestureRecognizer) {
timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(repeatAction), userInfo: nil, repeats: true)
}
func longPressEnded() {
timer.invalidate()
}
func longPressCancelled() {
timer.invalidate()
}
func repeatAction() {
deleteBackward()
}

Update NSArrayController correctly

I'm trying to populate NSTableView using NSArrayController, however can't get it to work. Here is my code:
class AppDelegate: NSObject, NSApplicationDelegate {
private let _spadList: SpadList
var spadList : SpadList {
get { return _spadList }
}
override init() {
_spadList = SpadList()
super.init()
}
func applicationDidFinishLaunching(_ aNotification: Notification) {
// Insert code here to initialize your application
createInitialData()
}
func applicationWillTerminate(_ aNotification: Notification) {
// Insert code here to tear down your application
}
func createInitialData() {
_spadList.chain = "CHAIN"
_spadList.service = "Service"
_spadList.dateString = "2016-12-12"
let firstEquity = Equity()
let anotherEquity = Equity()
firstEquity.name = "Apple"
firstEquity.tradePrice = 12.3
anotherEquity.name = "ORACLE"
anotherEquity.tradePrice = 45.7
_spadList.addEquity(equity: firstEquity)
_spadList.addEquity(equity: anotherEquity)
}
}
And this is ViewController:
class ViewController: NSViewController {
let appDelegate = NSApplication.shared().delegate as! AppDelegate
#IBOutlet weak var tableView: NSTableView!
func equities() -> [Equity]{
return appDelegate.spadList.equities
}
}
Content Array of the NSArrayController is bound to: ViewController.equities
The issue is that my manually created data are not populating itself into my tableView. If I move createInitialData() to ViewController class, they are correctly displayed.
What am I doing wrong?