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

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)
}
}

Related

Is there a reason a UIViewControllerRepresentable should never be a class?

Let's say that you don't really need SwiftUI features. I.e. you don't have import SwiftUI in your file. Instead, you only require
import protocol SwiftUI.UIViewControllerRepresentable
In general, you're going to have to involve a delegate object: an AnyObject at best, and usually, because the UIKit APIs are old, an NSObject.
The common pattern is to use a Coordinator class for that, and have the View itself be a struct, but is there always point in that indirection?
Here's an example which hasn't given me any trouble in practice:
import Combine
import MultipeerConnectivity
import protocol SwiftUI.UIViewControllerRepresentable
extension MCBrowserViewController {
final class View: NSObject {
init(
serviceType: String,
session: MCSession,
peerCountRange: ClosedRange<Int>? = nil
) {
self.serviceType = serviceType
self.session = session
self.peerCountRange = peerCountRange
}
private let serviceType: String
private unowned let session: MCSession
private let peerCountRange: ClosedRange<Int>?
private let didFinishSubject = CompletionSubject()
private let wasCancelledSubject = CompletionSubject()
}
}
// MARK: - internal
extension MCBrowserViewController.View {
var didFinishPublisher: AnyPublisher<Void, Never> { didFinishSubject.eraseToAnyPublisher() }
var wasCancelledPublisher: AnyPublisher<Void, Never> { wasCancelledSubject.eraseToAnyPublisher() }
}
// MARK: - private
private extension MCBrowserViewController {
typealias CompletionSubject = PassthroughSubject<Void, Never>
}
// MARK: - UIViewControllerRepresentable
extension MCBrowserViewController.View: UIViewControllerRepresentable {
func makeUIViewController(context: Context) -> MCBrowserViewController {
let browser = MCBrowserViewController(
serviceType: serviceType,
session: session
)
browser.delegate = self
if let peerCountRange = peerCountRange {
browser.minimumNumberOfPeers = peerCountRange.lowerBound
browser.maximumNumberOfPeers = peerCountRange.upperBound
}
return browser
}
func updateUIViewController(_: MCBrowserViewController, context _: Context) { }
}
// MARK: - MCBrowserViewControllerDelegate
extension MCBrowserViewController.View: MCBrowserViewControllerDelegate {
func browserViewControllerDidFinish(_: MCBrowserViewController) {
didFinishSubject.send()
}
func browserViewControllerWasCancelled(_: MCBrowserViewController) {
wasCancelledSubject.send()
}
}
I don't have a full detailed answer for your question, but your solution have some problems.
In SwiftUI, if we update a View, it calls init to recreate the View, and then call updateUIViewController.
In your case, whenever you update your View, not only your view is recreated, your two subjects will be recreated too, so anything attaches to the Publisher after the recreation won't receive events any more.
maybe that's the reason we prefer to use Coordinator.

iOS UITextView don't localize properly in storyboard

I have a storyboard with some text views on it. When I try to localize the storyboard (creating Storyboard.strings file), all of the UITextViews don't localize at all. UILabels are fine.
My config is as follow:
1 Base Storyboard file with 2 Storyboard.strings files
Storyboard Configuration
Storyboard.strings files are ok, its working with UILabels after all:
Storyboard.strings file
Have you found a solution for this problem?
I'm using Xcode 8.3, Swift 3, iOS 10.
You could just make a IBOutlet in Xcode and set the initial UITextView value in the didSet function.
E.g.
#IBOutlet var textView: UITextView {
didSet {
textView.text = NSLocalizedString("CUSTOM_LOCALISED_STRING", comment: "Comment.")
}
}
I ended up with this solution:
In a UIViewController I can access my UITextView-objects and force the localized text from Storyboard.strings to be used.
func fixTextViewStoryboardLocalization() {
guard storyboard != nil else {
return // No need to fix it if storyboard is not presented
}
let storyboardName = storyboard!.value(forKey: "name") as! String
for case let textView as UITextView in view.subviews {
if let ident = textView.restorationIdentifier {
textView.text = NSLocalizedString("\(ident).text", tableName: storyboardName, bundle: Bundle.main, value: "", comment: "")
}
}
}
Create a custom MyViewController (pick whatever name you want), call this function in viewDidLoad:
class MyViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
fixTextViewStoryboardLocalization()
}
}
Make sure the storyboard view controller is from class MyViewController:
MyViewController custom class in Storyboard
In order the code above to work, I need to set the Restoration ID for each UITextView in my Storyboard:
UITextView Restoration ID
Final step - localize the text view in Storyboard.strings:
/* Class = "UITextView"; text = "Base text"; ObjectID = "MyTextView-Restoration-ID"; */
"MyTextView-Restoration-ID.text" = "Localized text comes here";
This works for all my UITextViews in all my storyboards.

Swift 3 Create Reminder EKEventStore

I would like to save reminders to the default reminders location. But when I press my button I get a fatal error: unexpectedly found nil while unwrapping an Optional value... I am pretty new to this and most examples I locate are overly complicated or not in Swift 3.
class ViewController: UIViewController {
var eventStore: EKEventStore?
#IBOutlet weak var reminderText: UITextField!
#IBAction func setReminder(_ sender: Any) {
let reminder = EKReminder(eventStore: self.eventStore!)
reminder.title = "Go to the store and buy milk"
reminder.calendar = (eventStore?.defaultCalendarForNewReminders())!
do {
try eventStore?.save(reminder,
commit: true)
} catch let error {
print("Reminder failed with error \(error.localizedDescription)")
}
}
}
As its a simple piece of code I thought I would post my answer after I figured it out for any future swifters. I always like simple examples.
import UIKit
import EventKit
class ViewController: UIViewController {
var eventStore = EKEventStore()
var calendars:Array<EKCalendar> = []
// Not used at this time
#IBOutlet weak var reminderText: UITextField!
#IBAction func setReminder(_ sender: Any) {
let reminder = EKReminder(eventStore: self.eventStore)
reminder.title = "Go to the store and buy milk"
reminder.calendar = eventStore.defaultCalendarForNewReminders()
do {
try eventStore.save(reminder,
commit: true)
} catch let error {
print("Reminder failed with error \(error.localizedDescription)")
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// get permission
eventStore.requestAccess(to: EKEntityType.reminder, completion:
{(granted, error) in
if !granted {
print("Access to store not granted")
}
})
// you need calender's permission for the reminders as they live there
calendars = eventStore.calendars(for: EKEntityType.reminder)
for calendar in calendars as [EKCalendar] {
print("Calendar = \(calendar.title)")
}
}
override func viewWillAppear(_ animated: Bool) {
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
With the #adamprocter sample, we also need to add "NSRemindersUsageDescription" key with your message in info.plist file. I tried adding this as a comment but I am not eligible.

transitioningDelegate never called after Segue transition

So I'm trying to implement a custom animation as my app transitions from one View Controller to another, but for some reason the animateTransition function in my custom animation class is never called.
For the record, I'm using Xcode 8 and writing in Swift 3. The problem I'm trying to over come, is that the function is never called - I'll sort out the actual animation in the future, for now its
Here is the code in my CustomPresentAnimationController class, which should handle the transition animation...
import UIKit
class CustomPresentAnimationController: NSObject, UIViewControllerAnimatedTransitioning, UIViewControllerTransitioningDelegate, UINavigationControllerDelegate {
let duration = 0.5
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
print("Checking duration")
return duration
}
func animationController(forPresented presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
print("This ran 1")
return self
}
func presentationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
print("This ran 2")
return self
}
func animationController(navigationController: UINavigationController, animationControllerForOperation operation: UINavigationControllerOperation, fromViewController fromVC: UIViewController, toViewController toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
print("This ran 3")
return self
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
print("It's working!")
guard let fromView = transitionContext.view(forKey: UITransitionContextViewKey.from) else {
return
}
guard let toView = transitionContext.view(forKey: UITransitionContextViewKey.to) else {
return
}
let container = transitionContext.containerView
let screenOffDown = CGAffineTransform(translationX: 0, y: -container.frame.height)
let screenOffUp = CGAffineTransform(translationX: 0, y: container.frame.height)
container.addSubview(fromView)
container.addSubview(toView)
toView.transform = screenOffUp
UIView.animate(withDuration: duration, delay: 0.0, usingSpringWithDamping: 0.8, initialSpringVelocity: 0.8, options: [], animations: {
fromView.transform = screenOffDown
fromView.alpha = 0.5
toView.transform = CGAffineTransform.identity
toView.alpha = 1
}) { (success) in
transitionContext.completeTransition(success)
}
}
}
Here is the code for my ViewController (which both of my View Controllers reference)...
import UIKit
class ViewController: UIViewController, UINavigationControllerDelegate, UIViewControllerTransitioningDelegate {
override func viewDidLoad() {
if transitioningDelegate != nil {
print("Should do something...")
print(transitioningDelegate)
} else {
print("Transitioing Delegate set to nil")
}
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.navigationController?.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
let customPresentAnimationController = CustomPresentAnimationController()
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
print("doing our custom transition")
print(segue.destination)
let destination = segue.destination
destination.transitioningDelegate = customPresentAnimationController
}
}
When I run the code, and click on the button I provided, which links to my seance View Controller, and is set to 'Present Modally', the view changes with the standard transition (slides up from the bottom) - and the following is printed out to Xcode:
Transitioing Delegate set to nil
doing our custom transition
<moduleView.ViewController: 0x7fe427f09a40>
Should do something...
Optional(<moduleView.CustomPresentAnimationController: 0x60800002e980>)
Obviously the first line is just as the first view loads, all the rest shows that my transitionDelegate is set on the Segue destination, and is indeed loaded in as the second view loads, and that the transitionDelegate is set to CustomPresentAnimationController... yet none of the functions in that class are ever called as it never prints anything out from those functions.
Any help appreciated!
Ensure the method signature for implementing the delegate matches the updated Swift 3 syntax.

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?