Parse NSInternalInconsistencyException raises with PFImageView - swift

I'm experiencing an odd behaviour of Parse right now.
My App worked fine for weeks of development and never raised a 'NSInternalInconsistencyException' since project setup.
But I just implemented a PFImageView in my ProfileViewController (second VC in UITabBarController, therefore only showing when user is logged in) and my App keeps crashing with this error:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'You have to call setApplicationId:clientKey: on Parse to configure Parse.'
Of course I checked my Parse setup in func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool:
Parse.setApplicationId("myApplicationID", clientKey: "myClientKey")
Parse.enableLocalDatastore()
// This is where I used to activate Parse, but SO and Parse forums kept
// saying you should try to do this at the very beginning
ParseCrashReporting.enable()
PFAnalytics.trackAppOpenedWithLaunchOptionsInBackground(launchOptions, block: nil)
In my ProfileViewController this is where I load my image from Parse:
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
userImageView.file = user["profilePicture"] as PFFile
userImageView.loadInBackground { (image, error) -> Void in
if error != nil {
JSSAlertView().danger(self, title: "Loading Image Failed", text: "Please check your connection")
} else {
self.userImageView.image = image
}
}
}
Setting the instance variable of image:
var image: UIImage? {
// If User picked a new image, automatically update imageView
didSet {
userImageView.image = image
// Convert image to PNG and save in in Parse-Cloud
let imageData = UIImagePNGRepresentation(image)
let imageFile = PFFile(name: "profilePicture.png", data: imageData)
// Attach this file to our user
user["profilePicture"] = imageFile
user.saveInBackgroundWithBlock { (success, error) -> Void in
if error != nil {
JSSAlertView().danger(self, title: "Failed To Save Image", text: "Please try again saving your image!")
}
}
userImageView.file = user["profilePicture"] as PFFile
}
}
I have no clue what kind of connection could be between these things, but I didn't change anything else in the whole project.
Regards,

Ok, finally after hours of trial and error I found the solution for this problem.
You should never ever execute parse calls in the header of view controllers, as these calls could be executed before the API registration.
For example:
class ViewController: UIViewController {
// this will crash the app as above!
var user: PFUser! = PFUser.currentUser()
override func viewDidLoad() {
super.viewDidLoad()
// initialize the user here. This will work just fine
user = PFUser.currentUser()
}
}
Hope this saves you from having the same errors!

Related

Swift AWS Cognito error: Authentication delegate not set

I am developing an app in swift, and I use AWS mobile services for authentication and AWS Lambda to do some backend processing. I had everything working fine, and one day (after leaving the app for a month or so), it started throwing this error:
GetId failed. Error is [Error Domain=com.amazonaws.AWSCognitoIdentityProviderErrorDomain Code=-1000 "Authentication delegate not set" UserInfo {NSLocalizedDescription=Authentication delegate not set}]
Unable to refresh. Error is [Error Domain=com.amazonaws.AWSCognitoIdentityProviderErrorDomain Code=-1000 "Authentication delegate not set"
It's killing me, because it was already working. What could have changed?
In appDelegate, I have:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
// Uncomment to turn on logging, look for "Welcome to AWS!" to confirm success
AWSDDLog.add(AWSDDTTYLogger.sharedInstance)
AWSDDLog.sharedInstance.logLevel = .error
// Instantiate AWSMobileClient to get AWS user credentials
return AWSMobileClient.sharedInstance().interceptApplication(application, didFinishLaunchingWithOptions:launchOptions)
}
It actually throws the error before I make any invocation, so I think the lines above may be triggering the problem?
To login, I do the following, in my main viewController:
override func viewDidLoad() {
super.viewDidLoad()
if !AWSSignInManager.sharedInstance().isLoggedIn {
presentAuthUIViewController()
}
else{
getCredentials()
}
...
}
func presentAuthUIViewController() {
let config = AWSAuthUIConfiguration()
config.enableUserPoolsUI = true
config.backgroundColor = UIColor.white
config.logoImage = #imageLiteral(resourceName: "logoQ")
config.isBackgroundColorFullScreen = true
config.canCancel = true
AWSAuthUIViewController.presentViewController(
with: self.navigationController!,
configuration: config, completionHandler: { (provider:
AWSSignInProvider, error: Error?) in
if error == nil {
self.getCredentials()
} else {
// end user faced error while loggin in, take any required action here.
}
})
}
func getCredentials() {
let serviceConfiguration = AWSServiceConfiguration(region: .USEast1, credentialsProvider: nil)
let userPoolConfiguration = AWSCognitoIdentityUserPoolConfiguration(clientId: "id",
clientSecret: "secret",
poolId: "id")
AWSCognitoIdentityUserPool.register(with: serviceConfiguration, userPoolConfiguration: userPoolConfiguration, forKey: "key")
let pool = AWSCognitoIdentityUserPool(forKey: "key")
if let username = pool.currentUser()?.username {
userName = username
}
It loggs in, and I retrieve the user name.
Any tips? I followed some of the instructions in other posts but they didn't work, plus what most disconcerts me is that it was working!
Thanks in advance
I think this means that your refresh token expired.
So, not 100% sure of what was going on, but as I understand it there was a problem with the credentials for the user in the user pool. I reset the password and all started working fine again!
If anyone needs more details just ask, and if anyone understands this better let me know..

Integrating Facebook Login with Parse Swift 3

In my Xcode Project I already have a sign in feature that uses a user's username and password they created. Now I want to integrate a Facebook login in the project, but I am not completely sure how to do this. When someone makes an account through they way I have it now, they make and save a username and a password which can then be used in with PFUser.logIn(withUsername: ..., password: ...) for whenever they want to sign in again.
But with Facebook, I do not know what unique identifier I am suppose to save their account with. I know there is a Facebook id that I can extract, but how do I login the user in after I get this? Like I said before I currently use PFUser.logIn(withUsername: ..., password: ...) to log the users' in then I just use PFUser.current()?.username to get all data related to that user. I heard that I am suppose to use PFFacebookUtils.logInInBackground for this, but I already tried implementing it but when I press the "Continue with Facebook button", the app crashes (I screenshot error and placed it at bottom). I have copied my code of what I have so far. How do I integrate a signup with Facebook feature that will allow me to save a users Facebook id and what method do I use to sign the user in (i.e. PFFacebookUtils.logInInBackground)? Here's my code so far:
#IBOutlet var facebookSignUpButton: FBSDKLoginButton!
var fullnameFB = String()
var idFB = String()
var emailFB = String()
var isFBSignUp = Bool()
override func viewDidLoad() {
super.viewDidLoad()
signUpWithFacebook()
}
func signUpWithFacebook() {
facebookSignUpButton.readPermissions = ["email", "public_profile"]
facebookSignUpButton.delegate = self
self.view.addSubview(facebookSignUpButton)
}
func loginButton(_ loginButton: FBSDKLoginButton!, didCompleteWith result: FBSDKLoginManagerLoginResult!, error: Error!) {
if error != nil { //if theres an error
print(error)
} else if result.isCancelled { // if user cancels the sign up request
print("user cancelled login")
} else {
PFFacebookUtils.logInInBackground(with: result!.token!) { (user, error) in
if error == nil {
if let user = user {
if user.isNew {
print("User signed up and logged in through Facebook!")
} else {
print("User logged in through Facebook!")
}
if result.grantedPermissions.contains("email") {
if let graphRequest = FBSDKGraphRequest(graphPath: "me", parameters: ["fields": "email, name"]) {
graphRequest.start(completionHandler: { (connection, result, error) in
if error != nil {
print(error?.localizedDescription ?? String())
} else {
if let userDetails = result as? [String: String]{
print(userDetails)
self.fullnameFB = userDetails["name"]!
self.idFB = userDetails["id"]!
self.emailFB = userDetails["email"]!
self.isFBSignUp = true
}
}
})
}
} else {
print("didnt get email")
self.createAlert(title: "Facebook Sign Up", message: "To signup with Facebook, we need your email address")
}
} else {
print("Error while trying to login using Facebook: \(error?.localizedDescription ?? "---")")
}
} else {
print(error?.localizedDescription ?? String())
}
}
}
}
Console output:
2017-08-12 14:14:33.223472-0700 Project[2423:1001235] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'You must initialize PFFacebookUtils with a call to +initializeFacebookWithApplicationLaunchOptions'
*** First throw call stack:
(0x188042fe0 0x186aa4538 0x188042f28 0x100b8f934 0x100b90020 0x100b9032c 0x10019eee8 0x1001a0a64 0x100867598 0x10086e998 0x10086e4f0 0x100871a94 0x18b3610d4 0x101521a10 0x101526b78 0x187ff10c8 0x187feece4 0x187f1eda4 0x189989074 0x18e1dd364 0x1001ec288 0x186f2d59c)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)
As stated in the docs, you need to initialize PFFacebookUtils before using it, like so:
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
// CODE...
PFFacebookUtils.initializeFacebook(applicationLaunchOptions: launchOptions)
}
Important: Must be done after Parse setup (Parse.initialize...).

Entity for core data having nil for entityname

I am getting an error called "+entityForName: nil is not a legal NSManagedObjectContext parameter searching for entity name 'Person". The name of the entity is Person and the entity name is name which is set as a string. The whole point of this is so a user can be added with a username and this saves as core data. Any way to solve this issue? The appdelegate class is also in the code
class TableViewUsernameViewController: UIViewController {
#IBOutlet weak var tableView: UITableView!
var people: [NSManagedObject] = []
override func viewDidLoad() {
super.viewDidLoad()
title = "The List"
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
// Do any additional setup after loading the view.
}
#IBAction func addName(_ sender: Any) {
let alert = UIAlertController(title: "New Name",
message: "Add a new name",
preferredStyle: .alert)
let saveAction = UIAlertAction(title: "Save", style: .default) {
[unowned self] action in
guard let textField = alert.textFields?.first,
let nameToSave = textField.text else {
return
}
self.save(name: nameToSave)
self.tableView.reloadData()
}
let cancelAction = UIAlertAction(title: "Cancel",
style: .default)
alert.addTextField()
alert.addAction(saveAction)
alert.addAction(cancelAction)
present(alert, animated: true)
}
func save(name: String) {
guard let appDelegate =
UIApplication.shared.delegate as? AppDelegate else {
return
}
// 1
let managedContext =
appDelegate.persistentContainer.viewContext
// 2
let entity =
NSEntityDescription.entity(forEntityName: "Person",
in: managedContext)!
let person = NSManagedObject(entity: entity,
insertInto: managedContext)
// 3
person.setValue(name, forKeyPath: "name")
// 4
do {
try managedContext.save()
people.append(person)
} catch let error as NSError {
print("Could not save. \(error), \(error.userInfo)")
}
}
}
// MARK: - UITableViewDataSource
extension TableViewUsernameViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView,
numberOfRowsInSection section: Int) -> Int {
return people.count
}
func tableView(_ tableView: UITableView,
cellForRowAt indexPath: IndexPath)
-> UITableViewCell {
let person = people[indexPath.row]
let cell =
tableView.dequeueReusableCell(withIdentifier: "Cell",
for: indexPath)
cell.textLabel?.text =
person.value(forKeyPath: "name") as? String
return cell
}
}
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions:
[UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return true
}
func applicationWillResignActive(_ application: UIApplication) {
// Sent when the application is about to move from active to
inactive state. This can occur for certain types of temporary
interruptions (such as an incoming phone call or SMS message) or
when the user quits the application and it begins the transition to
the background state.
// Use this method to pause ongoing tasks, disable timers, and
invalidate graphics rendering callbacks. Games should use this
method to pause the game.
}
func applicationDidEnterBackground(_ application: UIApplication) {
// Use this method to release shared resources, save user data,
invalidate timers, and store enough application state information to
restore your application to its current state in case it is terminated
later.
// If your application supports background execution, this method
is called instead of applicationWillTerminate: when the user quits.
}
func applicationWillEnterForeground(_ application: UIApplication) {
// Called as part of the transition from the background to the
active state; here you can undo many of the changes made on entering
the background.
}
func applicationDidBecomeActive(_ application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while
the application was inactive. If the application was previously in the
background, optionally refresh the user interface.
}
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if
appropriate. See also applicationDidEnterBackground:.
// Saves changes in the application's managed object context before
the application terminates.
self.saveContext()
}
// MARK: - Core Data stack
lazy var persistentContainer: NSPersistentContainer = {
/*
The persistent container for the application. This implementation
creates and returns a container, having loaded the store for the
application to it. This property is optional since there are
legitimate
error conditions that could cause the creation of the store to
fail.
*/
let container = NSPersistentContainer(name: "QuizFinal")
container.loadPersistentStores(completionHandler: {
(storeDescription, error) in
if let error = error as NSError? {
// Replace this implementation with code to handle the
error appropriately.
// fatalError() causes the application to generate a crash
log and terminate. You should not use this function in a shipping
application, although it may be useful during development.
/*
Typical reasons for an error here include:
* The parent directory does not exist, cannot be created,
or disallows writing.
* The persistent store is not accessible, due to
permissions or data protection when the device is locked.
* The device is out of space.
* The store could not be migrated to the current model
version.
Check the error message to determine what the actual
problem was.
*/
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
// MARK: - Core Data Saving support
func saveContext () {
let context = persistentContainer.viewContext
if context.hasChanges {
do {
try context.save()
} catch {
// Replace this implementation with code to handle the
error appropriately.
// fatalError() causes the application to generate a crash
log and terminate. You should not use this function in a shipping
application, although it may be useful during development.
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \
(nserror.userInfo)")
}
}
}
}
//short-cut to access App Delegate
let ad = UIApplication.shared.delegate as! AppDelegate
let context = ad.persistentContainer.viewContext
I recently had this error and discovered if the Module was set to the 'Current Product Module' instead of the default 'Global' the problem was resolved.
To change the Module of an entity:
Select it.
Select its attributes.
Go to the class section.
Click on the 'Module' dropdown menu.
Select 'Current Product Module'
I think you are working an example from Ray's site (https://www.raywenderlich.com/). The code is nearly a replica. I had same issue, perplexing.
I inspected the core-data model: Select (FILE.xcdatamodelid) where FILE is name of your project. Somewhere, I clobbered the model. Simply add an entity, rename it to Person, add attribute called name with String type. Rebuild and run.

Firebase swift ios login system error Assertion failed/Exec_BAD_INSTRUNCTION (code=EXC_i386_INVOP, subcode=0x0)

Im trying to use the built in authentication system in firebase and followed this TuT to do so
Firebase Login Tutorial
I am able to run my app but when i go to login and type in a valid (or invalid) login email and password it crashes with this error in the console:
Assertion failed: (request.URL), function -[FSRWebSocket initWithURLRequest:protocols:queue:andUserAgent:], file /Users/vikrum/dev/git/firebase-client-objc/Firebase/Firebase/Libraries/SocketRocket/FSRWebSocket.m, line 302.
(lldb)
When I don't type anything and hit login it crashes with this error (i have measures to prevent the app from crashing because of this, possiably side affect of the bigger issue):
<pre>fatal error: unexpectedly found nil while unwrapping an Optional value</pre>
The inline errors below are the same w/ both above console errors
Edit: I have noticed that in the pod directory in my app in the framework and then ios folders the contents are (My hierarchy with red error **LINKhttp://i.stack.imgur.com/IHCQw.png) highlighted in red. The directory for the 4 frameworks was iPhoneOS9.0.sdk for some reason i only have a iPhoneOS.sdk and iPhoneOS9.2.sdk also the firebase and the other framework below it have strange directory locations [(They all go to this location **LINKhttp://i.stack.imgur.com/Z6dX5.png) and i cant for the life of me figure out how to fix it (i'm not totally sure this is the error causing my app to crash after I try to log in but its the only error I have seen so it must be)
Edit 2: i've been looking around and every recent tut to make an app as of at least ios 9 has been confusing me because of this, i have seen 2 separate apps tuts where i downloaded the finale project and i wasn't able to run it because in the pod dir(all where for firebase and ios 9.2 when made and had all the frameworks for firebase) it said "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.0.sdk/System/Library/Frameworks/CFNetwork.framework" and i cant change it because when i go to the little dir change button i have to get into the package contents of xcode and it wont let me do that
The inline error when I am redirected
Second files inline error (same)
Here is where i get directed when the app crashes and i get the error(2 places)
import Foundation
import Firebase
let BASE_URL = "https://baseball-pitcher-app.firebaseIO.comΩΩ"
let FIREBASE_REF = Firebase(url: BASE_URL)
var CURRENT_USER: Firebase
{
***let userID = NSUserDefaults.standardUserDefaults().valueForKey("uid") as! String*** ERROR IN THIS LINE
let currentUser = Firebase(url: "\(FIREBASE_REF)").childByAppendingPath("users").childByAppendingPath(userID)
return currentUser!
}
One thing I did find odd was that the error was in the logout button which is weird because i've never pressed it since the error occurred.
import UIKit
import Firebase
class LoginViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var userUsernameTextField: UITextField!
#IBOutlet weak var userPasswordTextField: UITextField!
#IBOutlet weak var logoutButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.userUsernameTextField.delegate = self;
self.userPasswordTextField.delegate = self;
}
override func viewDidAppear(animated: Bool)
{
super.viewDidAppear(animated)
if NSUserDefaults.standardUserDefaults().valueForKey("uid") != nil && CURRENT_USER.authData != nil
{
self.logoutButton.hidden = false
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
self.view.endEditing(true)
return false
}
#IBAction func loginButtonTapped(sender: AnyObject) {
let email = self.userUsernameTextField.text
let password = self.userPasswordTextField.text
if email != "" && password != ""
{
FIREBASE_REF.authUser(email, password: password, withCompletionBlock: { error, authData in
if error == nil
{
NSUserDefaults.standardUserDefaults().setValue(authData.uid, forKey: "uid")
print("Logged In :)")
self.logoutButton.hidden = false
}
else
{
print(error)
}
})
}
else
{
let alert = UIAlertController(title: "Error", message: "Enter Email and Password.", preferredStyle: UIAlertControllerStyle.Alert)
let action = UIAlertAction(title: "Ok", style: .Default, handler: nil)
alert.addAction(action)
self.presentViewController(alert, animated: true, completion: nil)
}
}
#IBAction func logoutButtonTapped(sender: AnyObject) {
CURRENT_USER.unauth()**** ERROR IN THIS LINE
NSUserDefaults.standardUserDefaults().setValue(nil, forKey: "uid")
self.logoutButton.hidden = true
}
The userId id is most likely nil, and in general it's better to catch the cases in which is it nil, like this
if let userID = NSUserDefaults.standardUserDefaults().valueForKey("uid") as? String {
print(userID) //do something with the user id here
} else {
print("The userID was nil.") //avoid the user id.
}
And the reason for the second error is that CURRENT_USER, since it never Auth'd to start with is now nil. Not sure why the button's IBAction is being called but check the actions and outlets in IB.
Also, the
var CURRENT_USER
is a little suspect.
Based on the name of the var, I would expect it to contain the Current User (as maybe a User Class?).
However when called, it returns a Firebase object which contains a path to the current users node (/appPath/users/users node) and no other user data. It doesn't appear to be populated when a user authenticates either.
Not sure if that was the intention or if it's used somewhere else, but doing this
CURRENT_USER.unauth()
may be an issue since it doesn't contain any auth data.

How can I do a Facebook login using Swift 2.0 and iOS 9.1?

I have added the latest Facebook SDK to my XCode 7.1 project written for iOS 9.1. Unfortunately all I know is Swift, not Objective C. Facebook's developer site documentation only has the documentation in Objective C. Every search on Google reveals documentation that is just too old because things have changed so much just in the past 6 months. So I'm kind of lost.
I did all the easy stuff with the plist file.
I was able to use:
import FBSDKCoreKit
import FBSDKLoginKit
I also added:
return FBSDKApplicationDelegate.sharedInstance().application(application, openURL: url, sourceApplication: sourceApplication, annotation: annotation)
and
return FBSDKApplicationDelegate.sharedInstance().application(application, didFinishLaunchingWithOptions: launchOptions)
To my AppDelegate.swift file. This all works and builds successfully. I have the correct frameworks added as well, obviously. Beyond this point I'm at a standstill because I don't know the syntax for adding a login button, for capturing what I assume would be returned json strings with tokens and other profile information I can use to store in the user's account, etc.
You're on the right track.
Have you set up your pList yet?
You're gonna have to add to your VC, add a login button, deal with delegate, and then deal with FB info. Something like (but not exactly) this:
class yourVC: UIViewController, FBSDKLoginButtonDelegate, UITextFieldDelegate
{
var loginView : FBSDKLoginButton = FBSDKLoginButton()
viewDidLoad() {
loginView.frame = CGRectMake(20, 20, theWidth-40, 40)
self.view.addSubview(loginView)
loginView.readPermissions = ["public_profile", "email", "user_friends","user_birthday"]
loginView.delegate = self
}
func loginButton(loginButton: FBSDKLoginButton!, didCompleteWithResult result: FBSDKLoginManagerLoginResult!, error: NSError!) {
if ((error) != nil)
{
//handle error
} else {
returnUserData()
}
}
func returnUserData()
{
let graphRequest : FBSDKGraphRequest = FBSDKGraphRequest(graphPath: "me", parameters: ["fields":"id,interested_in,gender,birthday,email,age_range,name,picture.width(480).height(480)"])
graphRequest.startWithCompletionHandler({ (connection, result, error) -> Void in
if ((error) != nil)
{
// Process error
print("Error: \(error)")
}
else
{
print("fetched user: \(result)")
let id : NSString = result.valueForKey("id") as! String
print("User ID is: \(id)")
//etc...
}
})
}
You're gonna have to play around with the returnData() part to get it right, but this code should get you 90% of the way there.
I've included a wide range of permissions (user age, interested in, etc), but you'll have to configure them yourself. Honestly this part (the hard part) is really similar with it's object C counterpart, which is much better documented. Just download some get projects where it's working, and try to parse them together into something that suits your fancy.
It can be hard to get it all working, but give it a go, and keep at it!
If you want to perform login from Facebook on click of your custom button, this will help:
#IBAction func onClickFacebookButton(sender: UIButton){
let login = FBSDKLoginManager()
login.loginBehavior = FBSDKLoginBehavior.SystemAccount
login.logInWithReadPermissions(["public_profile", "email"], fromViewController: self, handler: {(result, error) in
if error != nil {
print("Error : \(error.description)")
}
else if result.isCancelled {
}
else {
FBSDKGraphRequest(graphPath: "me", parameters: ["fields": "first_name, last_name, picture.type(large), email, name, id, gender"]).startWithCompletionHandler({(connection, result, error) -> Void in
if error != nil{
print("Error : \(error.description)")
}else{
print("userInfo is \(result))")
}
})
}
})
}