Local Parse Database gives error in SwiftUI - parse-platform

I'm trying to store objects in a local Parse datastore on the device itself. I get an error when retrieving the stored object: 'Method requires Pinning enabled.'
I've implemented 'Parse.enalbelLocalDatastore() in AppDelegate.swift. I tried to hard-code the object to be sure there was an object to retrieve.
let configuration = ParseClientConfiguration
{
$0.applicationId = "..."
$0.clientKey = "..."
$0.server = "..."
}
Parse.enableLocalDatastore()
Parse.initialize(with: configuration)
...
func blancoUser() {
let object = PFObject(className: "UserData")
object["id"] = (UUID().uuidString)
object["LoginName"] = "userName"
object["PinCode"] = "00000"
object["ScreenName"] = "test"
object["YearOfBirth"] = 0
object.pinInBackground()
}
...
let query = PFQuery(className: "UserData")
var users:[UserData] = [UserData]()
query.fromLocalDatastore()
query.findObjectsInBackground { (objects: [PFObject]?, error: Error?) in
if let error = error {
print(error.localizedDescription)
} else if let objects = objects
I want to get the variable 'users' with the locally stored user objects. What am I missing? Or does the ParseLocalDatastore work differently in SwiftUI.

Can you try to initialize the SDK like this?
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let parseConfig = ParseClientConfiguration {
$0.isLocalDatastoreEnabled = true
$0.applicationId = parseApplicationId
$0.clientKey = parseClientKey
$0.server = parseServerUrlString
}
Parse.initialize(with: parseConfig)
}
}
Reference: https://docs.parseplatform.org/ios/guide/#local-datastore

Related

Implementing AdMob Interstitial Ads in SwiftUI (5) and Xcode (12.4)

I am working on implementing Interstitial ads in my app and running into some confusion with the docs provided by Admob and the new SwiftUI app structure.
Here is the app.swift file, showing that I've implemented the GoogleMobileAds and started it in the didFinishLaunchingWithOptions method.
import SwiftUI
import GoogleMobileAds
#main
struct adamsCalcApp: App {
var calculator = Calculator()
#UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
WindowGroup {
ContentView().environmentObject(calculator)
}
}
}
class AppDelegate: NSObject, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
// Setup google admob instance
GADMobileAds.sharedInstance().start(completionHandler: nil)
return true
}
}
In my ContentView.swift File, I have the interstitial variable created like...
#State var interstitial: GADInterstitialAd?
Then on the main stack in the view, I call onAppear(perform: ) to load the ad, however I keep getting this error.
.onAppear(perform: {
let request = GADRequest()
GADInterstitialAd.load(withAdUnitID:"ca-app-pub-3940256099942544/4411468910",
request: request,
completionHandler: { [self] ad, error in
if let error = error {
return
}
interstitial = ad
interstitial?.fullScreenContentDelegate = self
}
)
})
"Cannot assign value of type 'ContentView' to type
'GADFullScreenContentDelegate?'"
I am feeling a bit clueless after trying a few different workarounds and trying to look up a setup that is like mine, AdMob docs still show how to implement with class ViewControllers and I would like to figure out how to do this is SwiftUI.
import SwiftUI
import GoogleMobileAds
import AppTrackingTransparency
import AdSupport
class AdsManager: NSObject, ObservableObject {
private struct AdMobConstant {
static let interstitial1ID = "..."
}
final class Interstitial: NSObject, GADFullScreenContentDelegate, ObservableObject {
private var interstitial: GADInterstitialAd?
override init() {
super.init()
requestInterstitialAds()
}
func requestInterstitialAds() {
let request = GADRequest()
request.scene = UIApplication.shared.connectedScenes.first as? UIWindowScene
ATTrackingManager.requestTrackingAuthorization(completionHandler: { status in
GADInterstitialAd.load(withAdUnitID: AdMobConstant.interstitial1ID, request: request, completionHandler: { [self] ad, error in
if let error = error {
print("Failed to load interstitial ad with error: \(error.localizedDescription)")
return
}
interstitial = ad
interstitial?.fullScreenContentDelegate = self
})
})
}
func showAd() {
let root = UIApplication.shared.windows.last?.rootViewController
if let fullScreenAds = interstitial {
fullScreenAds.present(fromRootViewController: root!)
} else {
print("not ready")
}
}
}
}
class AdsViewModel: ObservableObject {
static let shared = AdsViewModel()
#Published var interstitial = AdsManager.Interstitial()
#Published var showInterstitial = false {
didSet {
if showInterstitial {
interstitial.showAd()
showInterstitial = false
} else {
interstitial.requestInterstitialAds()
}
}
}
}
#main
struct YourApp: App {
let adsVM = AdsViewModel.shared
init() {
GADMobileAds.sharedInstance().start(completionHandler: nil)
}
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(adsVM)
}
}
Toggle the showInterstitial parameter in the AdsViewModel anywhere in the application and the advertisement will be shown.
In order to use the Admob docs with the newest SwiftUI release, you need to change this line...
.onAppear(perform: {
let request = GADRequest()
GADInterstitialAd.load(withAdUnitID:"ca-app-pub-3940256099942544/4411468910",
request: request,
completionHandler: { [self] ad, error in
if let error = error {
return
}
// Change these two lines of code
interstitial = ad
interstitial?.fullScreenContentDelegate = self
// To...
interstitial = ad
let root = UIApplication.shared.windows.first?.rootViewController
self.interstitial!.present(fromRootViewController: root!)
}
)
})

Storing/retriving a Codable Dictionary of structs in UserDefaults doesn't work for me

Swift (v 5/5.1) newbie here, having a hard time with Codables...hoping to get some advise from the experts here.
Okay, I have a simple dictionary from struct where the key is a string. I want to store the dictionary in UserDefaults (and later retrieve). There are some quite similar questions here, but these are mainly addressing nested struct's.
First attempt (error handling removed for simplicity):
public struct PriceStruct:Codable {
var myPrice: Double
var myTime: TimeInterval
var selected: Bool
var direction: Int
var myHigh, myLow: Double
enum CodingKeys: String, CodingKey {
case myPrice = "myPrice"
case myTime = "myTime"
case selected = "selected"
case direction = "direction"
case myHigh = "myHigh"
case myLow = "myLow"
}
}
var myPrices: [String: PriceStruct] = [:]
// [fill myPrices with some data...]
func savePrices() {
// error: Attempt to set a non-property-list object
UserDefaults.standard.set(myPrices, forKey: "prices")
}
func loadPrices() {
// obviously this doesn't work either
let myPrices = UserDefaults.standard.data(forKey: "prices")
}
While I assumed from the documentation, that UserDefaults is capable of storing dictionaries, it doesn't - at least for me.
Next thing I tried was using JSONEncoder like this:
// this time with prior JSON encoding
func savePrices() {
// this works
let json = try! JSONEncoder().encode(myPrices)
UserDefaults.standard.set(json as Data, forKey: "prices")
}
func loadPrices() {
// this doesn't work
let json = UserDefaults.standard.data(forKey: "prices")
let decoder = JSONDecoder()
let decoded = try! decoder.decode(PriceStruct.self, from json!)
}
Unfortunately I'm getting an error when trying to load data back from UserDefaults:
Swift.DecodingError.keyNotFound(CodingKeys(stringValue: "myPrice", intValue: nil), Swift.DecodingError.Context(codingPath: [], debugDescription: "No value associated with key CodingKeys(stringValue: \"myPrice\", intValue: nil) (\"myPrice\").", underlyingError: nil))
Other variants I tried is converting the encoded JSON to an UTF8 encoded string and storing/retrieving this one:
func savePrices() {
// this works too
let json = try! JSONEncoder().encode(myPrices)
UserDefaults.standard.set(String(data: json, encoding: .utf8), forKey: "prices")
}
func loadPrices() {
// and this doesn't work either
let json = UserDefaults.standard.string(forKey: "prices")!.data(using: .utf8)
}
So, from the error raised, CodingKeys seems to be the root of the problem. I tried to switch over using NSKeyedArchiver and NSKeyedUnarchiver` with no success.
I'm really wondering if there is a simple/universal solution to save/load a Dictionary in UserDefaults?
All your comments and suggestions are appreciated. Thanks!
I tried with the below code in my project that will work for me.
User Model
public protocol UserModel: Codable, PrimaryKey {
var id: String { get }
var firstName: String? { get }
var lastName: String? { get }
var userName: String? { get }
var emails: [String] { get }
}
public struct User: UserModel {
public let id: String
public let firstName: String?
public let lastName: String?
public let userName: String?
public let emails: [String]
public enum CodingKeys: String, CodingKey {
case id = "Id"
case firstName = "FirstName"
case lastName = "LastName"
case userName = "UserName"
case emails = "Emails"
}
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
do {
self.id = try container.decode(String.self, forKey: .id)
self.firstName = try container.decodeIfPresent(String.self, forKey: .firstName)
self.lastName = try container.decodeIfPresent(String.self, forKey: .lastName)
self.userName = try container.decodeIfPresent(String.self, forKey: .userName)
self.emails = try container.decodeIfPresent([String].self, forKey: .emails) ?? []
}
catch let error {
debugPrint(error)
throw error
}
}
}
I have stored in userDefault using below way
User Data Class
class UserData: NSObject
{
let userDefaultKey = "user_information"
var userData: User?
func getDictionary() -> [String: Data]
{
var dicInfo = [String: Data]()
do
{
let _userData = try JSONEncoder().encode(userData)
dicInfo["userData_default"] = _userData
}catch let error{
print("error while save data in User Default: \(error.localizedDescription)")
}
return dicInfo
}
func saveToDefault()
{
let userDefault = UserDefaults.standard
userDefault.set(getDictionary(), forKey: userDefaultKey)
userDefault.synchronize()
}
func loadFromDefault()
{
let userDefault = UserDefaults.standard
if let dicInfo = userDefault.object(forKey: userDefaultKey) as? [String: Data]
{
update(dicInfo)
}
}
func update(_ dictionaryInfo: [String: Data])
{
do
{
if let _userData_data = dictionaryInfo["userData_default"]
{
if let _userData = try? JSONDecoder().decode(User.self, from: _userData_data) {
userData = _userData
}
}
saveToDefault()
}catch let error{
print("error while load From Default data in User Default: \(error.localizedDescription)")
}
}
}
Hope this will help you.

I am setting up my sign up and login page using parse on xcode with swift but i keep getting a fatal error. Can somebody see what im doing wrong?

this is what i have so far:
import Foundation
import Parse
import UIKit
import Bolts
class SignUpViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var statusLabel: UILabel!
#IBOutlet weak var emailTextField: UITextField!
#IBOutlet weak var passwordTextField: UITextField!
#IBOutlet weak var createAccountButton: UIButton!
override func viewDidLoad()
{
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
emailTextField.delegate = self;
passwordTextField.delegate = self;
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func createAccountButtonPressed(sender: AnyObject) {
if verifyEmailDomain(self.emailTextField.text)
{
createAccount(self.emailTextField.text, password: self.passwordTextField.text)
}
else
{
//self.statusLabel.text = "Email domain is not valid.";
let alert = UIAlertView()
alert.title = "Invalid Email Domain"
alert.message = "Make sure you entered in your address correctly. If you did, ask your system about using PageMD! Thanks."
alert.addButtonWithTitle("Close")
alert.show()
}
}
func verifyEmailDomain(email: String) -> Bool
{
var isVerifiedDomain = false
let userDomain: String = (email.componentsSeparatedByString("#")).last!
//NSLog(userDomain)
let validDomainsFileLocation = NSBundle.mainBundle().pathForResource("ValidDomains", ofType: "txt")
var validDomainsFileContent = NSString(contentsOfFile: validDomainsFileLocation!, encoding: NSUTF8StringEncoding, error: nil)
// NSLog(validDomainsFileContent! as String)
let validDomains = validDomainsFileContent!.componentsSeparatedByString("\n")
for domain in validDomains
{
NSLog(domain as! NSString as String)
if userDomain == (domain as? NSString)
{
isVerifiedDomain = true
break
}
}
return isVerifiedDomain
}
func createAccount(email: String, password: String)
{
var newUser = PFUser()
newUser.username = email // We want the user to login only with their email.
newUser.email = email
newUser.password = password
newUser.signUpInBackgroundWithBlock { (succeeded: Bool, error: NSError?) -> Void in
if error == nil
{
// Account created successfully!
if succeeded == true
{
self.statusLabel.text = "Account created!"
}
}
else
{
if let errorField = error!.userInfo
{
self.statusLabel.text = (errorField["error"] as! NSString) as String
}
else
{
// No userInfo dictionary present
// Help from http://stackoverflow.com/questions/25381338/nsobject-anyobject-does-not-have-a-member-named-subscript-error-in-xcode
}
}
}
}
func textFieldShouldReturn(textField: UITextField) -> Bool
{
textField.resignFirstResponder()
return true;
}
}
when i run it i receive this in my terminal for xcode:
fatal error: unexpectedly found nil while unwrapping an Optional value
(lldb)
and highlighted in green is:
var validDomainsFileContent = NSString(contentsOfFile: validDomainsFileLocation!, encoding: NSUTF8StringEncoding, error: nil)
what can i do to avoid this error?
I'm trying to create a login that uses the emailVerified feature from parse but I keep receiving this error and cant save the email to the core or send the verification email to the user. What can i do to make this code work and stop the error from coming up?
In that case, the file at validDominsfileContent wasn't found. You need to make sure that the file is included in your Bundle.
To do that, open the Bundle-Resources:
Project > App target > Build Phases > Copy bundle resources
There you save your file. Now it should be found by Swift.

PFQuery not getting Object ID

The code below checks Parse to see if an email address has been verified. I am able to retrieve the object ID from Core Data (I saved it in a previous view controller) but when it comes to query.getObjectInBackgroundWithId(userID), userID is for some reason nil. I get the error:
Error: no results matched the query (Code: 101, Version: 1.6.0)
import UIKit
import CoreData
class HomePage: UIViewController{
#IBOutlet var emailMessage: UILabel!
//var userID: String!
override func viewDidLoad() {
super.viewDidLoad()
var appDel:AppDelegate = (UIApplication.sharedApplication().delegate as AppDelegate)
var context:NSManagedObjectContext = appDel.managedObjectContext!
var request = NSFetchRequest(entityName: "Users")
request.returnsObjectsAsFaults = false
var results: NSArray = context.executeFetchRequest(request, error: nil)!
var res = results [0] as NSManagedObject
var userID = res.valueForKey("userID") as String
println (userID) //Correct ID is retrieved here
var query = PFQuery(className:"User")
query.getObjectInBackgroundWithId(userID) { //ID becomes nil
(email: PFObject!, error: NSError!) -> Void in
if error == nil {
let checkEmail = email["emailVerified"] as Bool
if (checkEmail != true)
{
self.emailMessage.hidden = false
}
else
{
self.emailMessage.hidden = true
}
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
I think the problem lies in the way you're getting a PFQuery for the user. You should use the special user query:
var query = PFUser.query()
See Users - Querying, in the Parse docs.
The User table (as well as all other parse-managed classes) in parse is prefixed by underscore, so you should fix this line:
var query = PFQuery(className:"_User")

NSFetchRequest could not locate an NSEntityDescription

I know this is a duplicate of other questions but I've followed the answers to those questions and I still get the same error.
I think the error is coming from the fact that the code is trying to fetch the data when it has not even been saved (there is a delay in saving the data because I am getting it from Parse). Any ideas?
The exact error I get is:
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'NSFetchRequest could not locate an NSEntityDescription for entity name 'emailStatus''
-
import UIKit
import CoreData
class RegisterEmail: UIViewController {
var test1: Bool?
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func shouldPerformSegueWithIdentifier(identifier: String!, sender: AnyObject!) -> Bool {
if identifier == "passEmail" {
var query = PFUser.query()
query.getObjectInBackgroundWithId("vFu93HatwL") {
(User: PFObject!, error: NSError!) -> Void in
if error == nil {
NSLog("%#", User)
var checkEmail = User["emailVerified"] as Bool
println(checkEmail)
var appDel:AppDelegate = (UIApplication.sharedApplication().delegate as AppDelegate)
var context:NSManagedObjectContext = appDel.managedObjectContext!
var newEmail = NSEntityDescription.insertNewObjectForEntityForName("Email", inManagedObjectContext: context) as NSManagedObject
newEmail.setValue(checkEmail, forKey: "emailStatus")
context.save(nil)
println (newEmail)
println("Object Saved")
} else {
NSLog("%#", error)
}
}
var appDel:AppDelegate = (UIApplication.sharedApplication().delegate as AppDelegate)
var context:NSManagedObjectContext = appDel.managedObjectContext!
var request = NSFetchRequest(entityName: "emailStatus")
request.returnsObjectsAsFaults = false
var results: NSArray = context.executeFetchRequest(request, error: nil)!
if(results.count > 0)
{
var res = results [0] as NSManagedObject
test1 = res.valueForKey("emailStatus") as Bool
}
if (test1 == false) {
let alert = UIAlertView()
alert.title = "Error"
alert.message = "The email you have provided has not been verified."
alert.addButtonWithTitle("Dismiss")
alert.show()
return false
}
else {
return true
}
}
// by default, transition
return false
}
}
from op: "...everything is set up in the database file. Entity is called email and the attribute is emailStatus"
yet you try to fetch an entity emailStatus, where you likely want emails.
var request = NSFetchRequest(entityName: "emailStatus")
'typo'
fetch the right entity then: 'email'
var request = NSFetchRequest(entityName: "email")

Resources