I have the following code which should return the setting of the NotificationCenter, but when I run this code the variable notificationSetting returns nothing.
How can I solve this so that the application waits for the result?
func getNotificationSetting() -> String{
var notificationSetting = ""
UNUserNotificationCenter.current().getNotificationSettings { (settings) in
switch settings.authorizationStatus {
case .authorized, .provisional:
notificationSetting = "Authorized"
case .denied:
notificationSetting = "Denied"
case .notDetermined:
notificationSetting = "NotDetermined"
#unknown default:
notificationSetting = "NotDetermined"
}
}
return notificationSetting
}
getNotificationSettings execute asynchronously.
func getNotificationSetting(completionHandler: #escaping (String) -> Void) {
UNUserNotificationCenter.current().getNotificationSettings { (settings) in
switch settings.authorizationStatus {
case .authorized, .provisional:
completionHandler("Authorized")
case .denied:
completionHandler("Denied")
case .notDetermined:
completionHandler("NotDetermined")
#unknown default:
completionHandler("NotDetermined")
}
}
}
func getSettings() {
self.getNotificationSetting(completionHandler: { (notificationSetting) in
// do what you want
print(notificationSetting)
})
}
Related
I have this in my code and it works, however if I have other enums (not necessarily color) with a long list it gets tiresome. Is there a better way of having an enum with an associated value that also conforms to RawRepresentable?
public enum IconColor {
case regular
case error
case warning
case success
case custom(String)
public var value: Color {
return loadColor(self.rawValue)
}
}
extension IconColor: RawRepresentable {
public var rawValue: String {
switch self {
case .regular: return "icon_regular"
case .error: return "icon_error"
case .warning: return "icon_warning"
case .success: return "icon_success"
case .custom(let value): return value
}
}
public init(rawValue: String) {
switch rawValue {
case "icon_regular": self = .regular
case "icon_error": self = .error
case "icon_warning": self = .warning
case "icon_success": self = .success
default: self = .custom(rawValue)
}
}
}
There's not a general solution.
public var rawValue: String {
switch self {
case .custom(let value): return value
default: return "icon_\(self)"
}
}
public init(rawValue: String) {
self =
[.regular, .error, .warning, .success]
.first { rawValue == $0.rawValue }
?? .custom(rawValue)
}
So I wanted to check if I have access to the user location on iOS14 or not & I found this code but XCode(12) yells at me with this:
'authorizationStatus()' was deprecated in iOS 14.0
And here is the code:
func hasLocationPermission() -> Bool {
var hasPermission = false
if CLLocationManager.locationServicesEnabled() {
switch CLLocationManager.authorizationStatus() { // <= 'authorizationStatus()' was deprecated in iOS 14.0
case .notDetermined, .restricted, .denied:
hasPermission = false
case .authorizedAlways, .authorizedWhenInUse:
hasPermission = true
#unknown default:
hasPermission = false
}
} else {
hasPermission = false
}
return hasPermission
}
So what should I use instead?
iOS 14 and earlier version
func locationAuthorizationStatus() -> CLAuthorizationStatus {
let locationManager = CLLocationManager()
var locationAuthorizationStatus : CLAuthorizationStatus
if #available(iOS 14.0, *) {
locationAuthorizationStatus = locationManager.authorizationStatus
} else {
// Fallback on earlier versions
locationAuthorizationStatus = CLLocationManager.authorizationStatus()
}
return locationAuthorizationStatus
}
In iOS 14 'authorizationStatus()' is deprecated :
https://developer.apple.com/documentation/corelocation/cllocationmanager/1423523-authorizationstatus
You should use locationManagerDidChangeAuthorization instead:
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
switch manager.authorizationStatus {
case .authorizedAlways , .authorizedWhenInUse:
break
case .notDetermined , .denied , .restricted:
break
default:
break
}
switch manager.accuracyAuthorization {
case .fullAccuracy:
break
case .reducedAccuracy:
break
default:
break
}
}
iOS 14 Check user is allow permission
extension CLLocationManager {
func checkLocationPermission() {
if self.authorizationStatus != .authorizedWhenInUse && self.authorizationStatus != .authorizedAlways {
self.requestAlwaysAuthorization()
}
}
}
Use
self.LocationManager.checkLocationPermission()
ViewModel:
searchButtonInDidTapSubject.withLatestFrom(retailIdSubject.map { text in return text}).flatMapLatest { [unowned self] retailId in
return service.searchRetailPayCashBack(retailId: retailId, createdAt: self.createdDates, sig: self.sig).materialize();
}.subscribe(onNext: { [weak self] event in
switch (event) {
case .next(_):
self?.checkResultSubject.onNext(true)
break;
case .error(let error):
self?.errorSubject.onNext(error as! ErrorResponse);
break;
default:
break;
}
}).disposed(by: disposeBag);
// here i need to convert retailId , currentTime and accessToken
after that i send request api
private var sig: String{
get {
let accessToken = self.keychain.get(Constants.accessToken)
// ???
let newAccessToken = String((accessToken?.substring(with: 11..<21))!)
let retailid = ???
let newSig = "\(newAccessToken)\(self.createdDates)\(retailid)"
let md5Base64 = newSig.base64Encoded()
let md5Data = self.MD5(md5Base64!)
return String(md5Data!)
}
}
retailId needs to be equal to retailid
Not sure what are you trying to achieve, but it sounds like the sig should be generated each time you tap the button, because the retailId can be different.
searchButtonInDidTapSubject
.withLatestFrom(retailIdSubject.map { text in return text })
.flatMapLatest { [unowned self] retailId in
return service
.searchRetailPayCashBack(
retailId: retailId,
createdAt: self.createdDates,
sig: self.sig(withRetailId: retailId, createdDate: self.createdDates)
)
.materialize()
}
.subscribe(onNext: { [weak self] event in
switch (event) {
case .next(_):
self?.checkResultSubject.onNext(true)
break;
case .error(let error):
self?.errorSubject.onNext(error as! ErrorResponse);
break;
default:
break;
}
})
.disposed(by: disposeBag)
func sig(withRetailId retailId: String, createdDate: String) -> String {
let accessToken = self.keychain.get(Constants.accessToken)
// ???
let newAccessToken = String((accessToken?.substring(with: 11..<21))!)
let newSig = "\(newAccessToken)\(createdDate)\(retailId)"
let md5Base64 = newSig.base64Encoded()
let md5Data = self.MD5(md5Base64!)
return String(md5Data!)
}
I'm new to asking questions.
I need help in creating a feature of the app which is to unlock the tabbar when a purchase is made.
I used this code to lock my tabbar which is in the override func viewDidLoad()
I would really appreciate if someone could sort this out for me! I have been researching all day with no answers. Thanks!
if let arrayOfTabBarItems = tabBarController?.tabBar.items as AnyObject as? NSArray,let tabBarItem1 = arrayOfTabBarItems[0] as? UITabBarItem {
tabBarItem1.isEnabled = true
}
if let arrayOfTabBarItems = tabBarController?.tabBar.items as AnyObject as? NSArray,let tabBarItem2 = arrayOfTabBarItems[1] as? UITabBarItem {
if nonConsumablePurchaseMade == true {
tabBarItem2.isEnabled = true
print("done")
} else
{
tabBarItem2.isEnabled = false
print("failed")
}
}
if let arrayOfTabBarItems = tabBarController?.tabBar.items as AnyObject as? NSArray,let tabBarItem3 = arrayOfTabBarItems[2] as? UITabBarItem {
tabBarItem3.isEnabled = false
}
if let arrayOfTabBarItems = tabBarController?.tabBar.items as AnyObject as? NSArray,let tabBarItem4 = arrayOfTabBarItems[3] as? UITabBarItem {
tabBarItem4.isEnabled = false
}
and this might help. They are the functions for the purchases.
func purchaseProduct(with id: String){
SwiftyStoreKit.retrieveProductsInfo([id]) { result in
if let product = result.retrievedProducts.first {
SwiftyStoreKit.purchaseProduct(product, quantity: 1, atomically: true) { result in
switch result {
case .success(let product):
// fetch content from your server, then:
if product.needsFinishTransaction {
SwiftyStoreKit.finishTransaction(product.transaction)
}
case .error(let error):
switch error.code {
case .unknown: print("Unknown error. Please contact support")
case .clientInvalid: print("Not allowed to make the payment")
case .paymentCancelled: break
case .paymentInvalid: print("The purchase identifier was invalid")
case .paymentNotAllowed: print("The device is not allowed to make the payment")
case .storeProductNotAvailable: print("The product is not available in the current storefront")
case .cloudServicePermissionDenied: print("Access to cloud service information is not allowed")
case .cloudServiceNetworkConnectionFailed: print("Could not connect to the network")
case .cloudServiceRevoked: print("User has revoked permission to use this cloud service")
}
}
}
}
}
}
func verifyPurchase(with id: String , sharedSecret: String) {
let appleValidator = AppleReceiptValidator(service: .production, sharedSecret: sharedSecret)
SwiftyStoreKit.verifyReceipt(using: appleValidator) { result in
switch result {
case .success(let receipt):
let productId = "myID"
// Verify the purchase of Consumable or NonConsumable
let purchaseResult = SwiftyStoreKit.verifyPurchase(
productId: id,
inReceipt: receipt)
switch purchaseResult {
case .purchased(let receiptItem):
print("\(productId) is purchased: \(receiptItem)")
if self.product_ID == self.productId {
// Save your purchase locally (needed only for Non-Consumable IAP)
self.nonConsumablePurchaseMade = true
UserDefaults.standard.set(self.nonConsumablePurchaseMade, forKey: "nonConsumablePurchaseMade")
}
case .notPurchased:
print("The user has never purchased \(productId)")
}
case .error(let error):
print("Receipt verification failed: \(error)")
}
}
}
#objc func returnTextView(gesture: UIGestureRecognizer) {
guard activeField != nil else {
return
}
activeField?.resignFirstResponder()
activeField = nil
}
All, I created the following function:
func determineStatus() -> Bool {
let status = ABAddressBookGetAuthorizationStatus()
var ok = false
switch status {
case .NotDetermined:
println("Asking for Grant")
ABAddressBookRequestAccessWithCompletion(nil) {
(granted:Bool, err:CFError!) in
ok = granted
println("Granted Status: \(granted)")
}
case .Authorized:
println("Authorized")
ok = true
case .Restricted:
println("Restricted")
ok = false
case .Denied:
println("Denied")
ok = false
}
if ok == true {
println("Creating AB Instance")
return self.createAddressBook()
} else {
self.adbk = nil
println("Not Authorized")
return false
}
}
And I call it from within my Master - Detail View.
The first time I call it the view appears before the alert window asking for authorization, and it's empty.
I get in my console:
Asking for Grant
Not Authorized
And, after I authorize:
Granted Status: true
So the if ok == true part of determineStatus get executed before the ABAddressBookRequestAccessWithCompletion(nil) completes.
The second time I run it I get the data displayed.
How can I change determineStatus in order for the if ok == true statement to be executed after ABAddressBookRequestAccessWithCompletion(nil) finishes?
I found a working solution here.
Credits go to #matt, I just copy/pasted his code and added a call to the class for this example:
class MyAddressBook {
var adbk : ABAddressBook!
func createAddressBook() -> Bool {
if self.adbk != nil {
return true
}
var err : Unmanaged<CFError>? = nil
let adbk : ABAddressBook? = ABAddressBookCreateWithOptions(nil, &err).takeRetainedValue()
if adbk == nil {
println(err)
self.adbk = nil
return false
}
self.adbk = adbk
return true
}
func determineStatus() -> Bool {
let status = ABAddressBookGetAuthorizationStatus()
switch status {
case .Authorized:
return self.createAddressBook()
case .NotDetermined:
var ok = false
ABAddressBookRequestAccessWithCompletion(nil) {
(granted:Bool, err:CFError!) in
dispatch_async(dispatch_get_main_queue()) {
if granted {
ok = self.createAddressBook()
}
}
}
if ok == true {
return true
}
self.adbk = nil
return false
case .Restricted:
self.adbk = nil
return false
case .Denied:
self.adbk = nil
return false
}
}
func getContactNames() {
if !self.determineStatus() {
println("not authorized")
return
}
let people = ABAddressBookCopyArrayOfAllPeople(adbk).takeRetainedValue() as NSArray as [ABRecord]
for person in people {
println(ABRecordCopyCompositeName(person).takeRetainedValue())
}
}
}
And elsewhere, likely in a controller (I've tested in viewDidLoad of a simple test app, it works well), do this:
let myABInstance = MyAddressBook()
let result = myABInstance.determineStatus()
println("Succeeded: \(result)")
myABInstance.getContactNames()
What I've got:
true
Kate Bell
Daniel Higgins Jr.
John Appleseed
Anna Haro
Hank M. Zakroff
David Taylor