Currently there is no suggestion input for TextField.
I found an extension to use TextField with suggestions on WatchOS but this one is not working on a view which navigated with NavigationLink
Here is the wrapper code;
import Foundation
import SwiftUI
extension View {
typealias StringCompletion = (String) -> Void
func presentInputController(withSuggestions suggestions: [String], completion: #escaping StringCompletion) {
WKExtension.shared()
.visibleInterfaceController?
.presentTextInputController(withSuggestions: suggestions,
allowedInputMode: .allowEmoji) { result in
guard let result = result as? [String], let firstElement = result.first else {
completion("")
return
}
completion(firstElement)
}
}
}
I'm looking forward to your suggestions too :))
Related
I am trying to build a SwiftUI tvOS app.
As you can see here, I am trying to create a SwiftUI View using a UIViewControllerRepresentable, specifically for the DDDevicePickerViewController.
However, I noticed that there is no DDDevicePickerViewControllerDelegate while I was trying to implement it, which is needed according to Paul Hudson's tutorial. How can I use the DevicePickerView in SwiftUI?
I tried to use this code to create it, so when I use it, I just get a black screen with no errors in the logs:
import Foundation
import SwiftUI
import DeviceDiscoveryUI
public struct DDevicePickerView: UIViewControllerRepresentable {
let viewController: DDDevicePickerViewController
public init() {
// Create the view controller for the device picker.
let devicePicker = DDDevicePickerViewController(browseDescriptor: .applicationService(name: "TicTacToe"),
parameters: applicationServiceParameters())
self.viewController = devicePicker!
}
public func makeUIViewController(context: Context) -> DDDevicePickerViewController {
let gkVC = viewController
return gkVC
}
public func updateUIViewController(_ uiViewController: DDDevicePickerViewController, context: Context) {
return
}
}
SwiftUI already has a wrapper DevicePicker
But if you want to wrap it yourself, start with something like this and then you just have to figure out how to get the async endpoint result. It is quite unusual to have view controllers be async like this.
import Foundation
import SwiftUI
import DeviceDiscoveryUI
public struct DevicePicker: UIViewControllerRepresentable {
#Binding var isPresented: Bool
public func makeUIViewController(context: Context) -> UIViewController {
UIViewController()
}
public func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
if isPresented {
if uiViewController.presentedViewController != nil {
return
}
let = picker DDDevicePickerViewController(browseDescriptor: .applicationService(name: "TicTacToe"), parameters: applicationServiceParameters())
uiViewController.present(picker, animated: !context.transaction.disablesAnimations)
}
else {
uiViewController.presentedViewController?.dismiss()
}
}
}
I am going to make a relation between Siri Intent and React-native, but I have an error when I am going to call a class from Intent Extension.
how can I call swift class from different target in Intent Extension. The target of my ReactIntegration.swift is main project which is going to be called from GetCommandIntentHandler.swift (intent extension). Here is the source of two files.
The root and Target of ReactIntegration.swift
the source code is
import Foundation
#objc(ReactIntegration)
class ReactIntegration: RCTEventEmitter {
private var count = 0
#objc
func AskRequestFromEnergica(request: String) {
sendEvent(withName: "AskRequestFromEnergica", body: ["request": request])
}
override func supportedEvents() -> [String]! {
return ["AskRequestFromEnergica"]
}
override func constantsToExport() -> [AnyHashable : Any]! {
return ["initialCount": count]
}
override static func requiresMainQueueSetup() -> Bool {
return true
}
}
The target of GetCommandIntentHandler.swift
the source code is
import Foundation
class GetCommandInentHandler: NSObject, GetCommandIntentHandling{
func handle(intent: GetCommandIntent, completion: #escaping (GetCommandIntentResponse) -> Void) {
let req = intent.request!
let res = "the result is " + req
let ri = ReactIntegration()
ri.AskRequestFromEnergica(res);
let response = GetCommandIntentResponse.success(result: res)
completion(response)
}
the error is 'Cannot find 'ReactIntegration' in scope'.
Please let me know how to solve it. Thanks
I've been grinding on this issue for quite a few days now and it seems like SwiftUI's relative "newness" doesn't seem to help me with this.
My gut feeling is that I'm somehow using CNContactViewControllerDelegate wrong but both Apple's documentation as well as other questions on SO make it seem like it should work. Maybe, it is also caused by .sheet's handling, but I wasn't able to isolate the issue as well. Not wrapping NewContactView inside NavigationView also made no difference and removed the default navigation bar (as expected).
I'm showing the CNContactViewController with init(forNewContact:) to give the app's users an ability to add new contacts. Persisting and everything works fine, however, none of the delegate's functions seem to get called.
Neither dismissing the modal with the "swipe to dismiss" gesture introduced in iOS 13 calls the delegate function, nor using the navigation buttons provided by CNContactViewController.
import Foundation
import SwiftUI
import ContactsUI
struct NewContactView: UIViewControllerRepresentable {
class Coordinator: NSObject, CNContactViewControllerDelegate, UINavigationControllerDelegate {
func contactViewController(_ viewController: CNContactViewController, didCompleteWith contact: CNContact?) {
if let c = contact {
self.parent.contact = c
}
viewController.dismiss(animated: true)
}
func contactViewController(_ viewController: CNContactViewController, shouldPerformDefaultActionFor property: CNContactProperty) -> Bool {
return true
}
var parent: NewContactView
init(_ parent: NewContactView) {
self.parent = parent
}
}
#Binding var contact: CNContact
init(contact: Binding<CNContact>) {
self._contact = contact
}
typealias UIViewControllerType = CNContactViewController
func makeCoordinator() -> Coordinator {
return Coordinator(self)
}
func makeUIViewController(context: UIViewControllerRepresentableContext<NewContactView>) -> NewContactView.UIViewControllerType {
let vc = CNContactViewController(forNewContact: CNContact())
vc.delegate = makeCoordinator()
return vc
}
func updateUIViewController(_ uiViewController: NewContactView.UIViewControllerType, context: UIViewControllerRepresentableContext<NewContactView>) {
}
}
The view's code for showing the controller looks like this:
.sheet(isPresented: self.$viewModel.showNewContact, onDismiss: { self.viewModel.fetchContacts() }) {
NavigationView() {
NewContactView(contact: self.$viewModel.newContact)
}
}
Thank you for any pointers! Rubberducking sadly didn't help...
SwiftUI creates coordinator by itself and provides it to representable in context, so just use
func makeUIViewController(context: UIViewControllerRepresentableContext<NewContactView>) -> NewContactView.UIViewControllerType {
let vc = CNContactViewController(forNewContact: CNContact())
vc.delegate = context.coordinator // << here !!
return vc
}
In SwiftUI, I have a network request running in scenedelegate, scenedidbecomeactive. I don't know which view the user will be on when the app becomes active, but I want to present an alert if the data in the network request changes. I simplified the code below, so it's easy to read...
func sceneDidBecomeActive(_ scene: UIScene) {
let customClass = CustomClass()
customClass.performNetworkRequest()
In CustomClass, i have...
func performNetWorkRequest() {
URLSession.shared.dataTask(with: url) { (data, response, error) in
if let d = data {
let response = try JSONDecoder().decode(DetailResponse.self, from: d)
DispatchQueue.main.async {
//Here is where I want to either present an alert, but I can't figure out how to.
//OR do i put a func in SceneDeletegate to present the alert on the window.rootviewcontroller and then just call that func from here?
}
Any help is much appreciated!
Paul has a point - here's a possible implementation:
// In CustomClass.swift
import Combine
class CustomClass : ObservableObject {
#Published var dataRecieved = PassthroughSubject<DetailResponse, Never>()
init() {
performNetWorkRequest()
}
func performNetWorkRequest() {
URLSession.shared.dataTask(with: url) { (data, response, error) in
let response = try JSONDecoder().decode(DetailResponse.self, from: data)
DispatchQueue.main.async {
self.dataRecieved.send(response)
}
}
.resume()
}
}
// In SomeView.swift
import SwiftUI
import Combine
struct ContentView: View {
#State var showAlert = false
var customClass = CustomClass()
var body: some View {
Text("Hello, World!")
.onReceive(customClass.dataRecieved) { _ in
self.showAlert = true
}
.alert(isPresented: $showAlert) {
// your alert
}
}
}
Notice I didn't mention the SceneDelegate in any of these - this approach (called MVVM) is more flexible, in my opinion - besides, the way it is set up, performNetWorkRequest() will be executed as soon as your view is initialized, anyway.
You can also tweak the PassthroughSubject - I didn't know if you needed the DetailResponse or not.
Hope this helped!
Edit:
I just reread your question and it seems that this implementation is at fault as you noted there was no way to know what view the user would be on in the case of a network change. In that case, you can feed the same instance of CustomClass in your SceneDelegate as an EnvironmentObject.
I'm having a problem when overriding a function from the ReSwift Pod. I've got the following mock class:
import Foundation
import Quick
import Nimble
import RxSwift
#testable import MainProject
#testable import ReSwift
class MockReSwiftStore: ReSwift.Store<MainState> {
var dispatchDidRun: Bool = false
var subscribeWasTriggered: Bool = false
init() {
let reducer: Reducer<MainState> = {_, _ in MainState() }
super.init(reducer: reducer, state: nil)
}
required init(
reducer: #escaping (Action, State?) -> State,
state: State?,
middleware: [(#escaping DispatchFunction, #escaping () -> State?) -> (#escaping DispatchFunction) -> DispatchFunction]) {
super.init(reducer: reducer, state: state, middleware: middleware)
}
override func subscribe<SelectedState, S>(
_ subscriber: S,
transform: ((Subscription<MainState>) -> Subscription<SelectedState>)?)
where S: StoreSubscriber,
S.StoreSubscriberStateType == SelectedState {
subscribeWasTriggered = true
}
}
}
And when overriding the subscribe method I'm getting following errors
Then when using autocomplete it also shows 2 occurences:
However when looking for the original function there's only one which looks like this
open func subscribe<SelectedState, S: StoreSubscriber>(
_ subscriber: S, transform: ((Subscription<State>) -> Subscription<SelectedState>)?
) where S.StoreSubscriberStateType == SelectedState
{
// Create a subscription for the new subscriber.
let originalSubscription = Subscription<State>()
// Call the optional transformation closure. This allows callers to modify
// the subscription, e.g. in order to subselect parts of the store's state.
let transformedSubscription = transform?(originalSubscription)
_subscribe(subscriber, originalSubscription: originalSubscription,
transformedSubscription: transformedSubscription)
}
This is my compiler output
I'm out of ideas so any help is greatly appreciated
Thanks!
Here is your issue:
class Some<T> {
func echo() {
print("A")
}
}
extension Some where T: Equatable {
func echo() {
print("B")
}
}
class AnotherSome: Some<String> {
override func echo() {
print("Doesn't compile")
}
}
The problem is: ReSwift developers declare Store.subscribe behavior as a part of interface and as a part of extension (I am not sure why they chose to do it instead of introducing other objects). Swift can't figure out which part you are trying to override and thus it doesn't compile. Afaik there are no language instruments which allow you to resolve this issue.
A possible solution is to implement MockStore as a StoreType and use Store object to implement behavior for StoreType interface.