How do I check if userDefault is empty? - swift

I'm trying to deny access to a certain view controller if the userDefault is empty, but the code doesn't seem to work. To be a bit more clear, I'm saving a favorite-list to a userDefault. This is my code:
if UserDefaults.standard.array(forKey: "favorites") == nil {
navigationController?.popToRootViewController(animated: true)
return
}
The error is Index out of range, which means that the whole block is ignored (the code after this block runs and since the user default is empty it crashes when trying to retrieve information that isn't there).
The funny thing is, the code works the first time I try to enter the viewController (it denies me access). But if I favorite mark an object (save to userDefault), then un-favorite the same object (userDefault becomes empty), and enter the viewController, the program crashes.
I have tried:
if let favExist = UserDefaults.standard.array(forKey: "favorites") {
print("")
print("FAV EXISTS")
print("")
}else {
print("")
print("NOPE")
print("")
navigationController?.popToRootViewController(animated: true)
return
}
...and the same problem persists. In print() the log tells me FAV EXISTS after I favorite mark, then un-favorite mark, then try accessing the page (even though the userDefault now should be empty).
I have also tried code from other threads. The suggested code to solve my problem from the other thread was:
let defaults = UserDefaults.standard
if (!defaults.bool(forKey: "favorites")) {
defaults.set(true, forKey: "favorites")
}
I'm not really sure how to implement it though? Where do I use this? And what does it do?
Any idea what's wrong?

It´s enough to do this:
if let favorites = UserDefaults.standard.array(forKey: "favorites") {
// userDefault has a value
} else {
// userDefault is nil (empty)
}
Update:
You need to make a check within the if-statement if your arrat has any values too:
if let favorites = UserDefaults.standard.array(forKey: "favorites") {
print("Favorites exists")
if favorites.isEmpty {
print("Favorites is empty")
} else {
print("Favorites is not empty, it has \(favorites.count) items")
}
} else {
print("Favorites is nil")
}

When you set the UserDefaults Array also set a BOOL to UserDefaults. When you recover the Bool it won't crash even if it hasn't been set.
var favouritesset = UserDefaults.standard.bool(forKey: "favoritesset")
if favouritesset == true {
//Then Recover the Array
var array = UserDefaults.standard.array(forKey: "favorites")
}

OK, Rashwan L solved it for me. Thing was, my code (and suggested code by others) checked whether or not userDefault existed or not - it didn't bother whether there was a value stored or not. To work around the problem, I had to test if favExist.count == 0 was true. If true, user is blocked from the page and prevented from accessing the rest of the code. Se below:
if let favExist = UserDefaults.standard.array(forKey: "favorites") {
if(favExist.count == 0)
{
navigationController?.popToRootViewController(animated: true)
return
}
}else {
navigationController?.popToRootViewController(animated: true)
return
}

You do like this:
if UserDefaults.standard.array(forKey: "favs") != nil {
// userDefault has a value
} else {
// userDefault is nil (empty)
}

Related

Hiding button if swift Coredata function is blank

I have a problem with some code. I have a function called attachments. It calls on a DatabaseManager to a specific function getttachmentdata. This calls on coredata to see if a user has uploaded an image and call on it. If it has it I have another part of the code where the user clicks on a button and it shows that image.
The problem is that when the data is blank or there is nothing uploaded I wanted the button to be disabled. This might be a simple fix but I am not quite sure actually.
let attachments = DataBaseManager().getAttachmentData()
if attachments.isEmpty {
btnProofOfDelivery.isHidden = true
btnProofOfDelivery.isEnabled = false
}
I wrote the code above, however, when I tried running my program it still displayed the button that I wanted to disappear. Running without the if statement makes the button disappear.
code for getattachments
func getAttachmentData()-> Array<Data>{
var data1 = [Data]()
let context = CoreData.sharedCoreData.managedObjectContext
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Attachments")
do {
let result = try context.fetch(request)
print(result)
for data in result as! [NSManagedObject] {
print(data.value(forKey: "attachment") as! Data)
data1.append(data.value(forKey: "attachment") as! Data)
}
if data1.count == 0 {
return [Data()]
}else{
return data1
}
} catch {
return [Data()]
}
}
Below is your bug, if the fetch doesn't return anything you return a new Data object
if data1.count == 0 {
return [Data()]
}
You of course meant to write
if data1.count == 0 {
return [Data]()
}
and some issue in catch
or you can just remove all of that since data1 is properly initialised so you can just return it either way so the code after the for {} loop can then be reduced to
return data1
} catch {
print(error)
}
}

Core Data Attribute reset in Swift

In my application, I have set up a Core Data entity called "Finances". For now it has 2 attributes: money and net-worth.
I wish to write a function that each time it is called, it deletes all results for a specific entity. An example might be:
func resetAttribute(attribute: String) {
}
PS: I have found on the internet a function which was engineered to only delete a specific element of an attribute, which matched to a string. I have modified the code in the following way:
func resetTest() {
if let dataAppDelegatde = UIApplication.shared.delegate as? AppDelegate {
let mngdCntxt = dataAppDelegatde.persistentContainer.viewContext
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "ApplicationFinances")
let predicate = NSPredicate(format: "money != %#", "vdavduabsdpansuryiubj")
fetchRequest.predicate = predicate
do {
let result = try mngdCntxt.fetch(fetchRequest)
print(result.count)
if result.count > 0 {
for object in result {
print(object)
mngdCntxt.delete(object as! NSManagedObject)
}
}
} catch{
}
}
}
Meaning that if money wouldn't have been equals to vdavduabsdpansuryiubj (Meaning never of course) it would have deleted the other values. But this didn't seem to work.
What happens when you run the function? Does it throw an error? Or does it print just fine and runs fine but nothing actually happens when you reload the core data? If this is the case, try adding:
do {
try mngdCntxt.save()
} catch {}
Right after the for loop is over

How Save UILocalNotifications in CoreData

Answer is below, image is here:
I was searching how to do this for a couple of days and was only able to find people who stored UILocalNotificaations in NSUserDefaults. Saving these in NSUserDefaults seemed wrong to me because it is supposed to be used for small flags. I just now finally figured out how to store notifications in CoreData. This is Using Xcode 7.3.1 and Swift 2.2
First off you need to create a new entity in your CoreDataModel
and then add a single attribute to it. the attribute should be of type Binary Data I named my table/entity "ManagedFiredNotifications" and my attribute "notification". it should look like this:
Image linked in Question above.
Next you need to add an extension to UILocalNotification it should go like this:
extension UILocalNotification {
func save() -> Bool {
let appDelegate = UIApplication.sharedApplication().delegate as? AppDelegate
let firedNotificationEntity = NSEntityDescription.insertNewObjectForEntityForName("ManagedFiredNotifications", inManagedObjectContext: appDelegate!.managedObjectContext)
guard appDelegate != nil else {
return false
}
let data = NSKeyedArchiver.archivedDataWithRootObject(self)
firedNotificationEntity.setValue(data, forKey: "notification")
do {
try appDelegate!.managedObjectContext.save()
return true
} catch {
return false
}
}
}
Now for saving a notification all you need to do is call
UILocalNotification.save()
On the notification you would like to save. my notifications were named 'notification' so I would call notification.save()
To retrieve a notification you need a method like this
func getLocalFiredNotifications() -> [UILocalNotification]? {
let managedObjectContext = (UIApplication.sharedApplication().delegate as? AppDelegate)!.managedObjectContext
let firedNotificationFetchRequest = NSFetchRequest(entityName: "ManagedFiredNotifications")
firedNotificationFetchRequest.includesPendingChanges = false
do {
let fetchedFiredNotifications = try managedObjectContext.executeFetchRequest(firedNotificationFetchRequest)
guard fetchedFiredNotifications.count > 0 else {
return nil
}
var firedNotificationsToReturn = [UILocalNotification]()
for managedFiredNotification in fetchedFiredNotifications {
let notificationData = managedFiredNotification.valueForKey("notification") as! NSData
let notificationToAdd = NSKeyedUnarchiver.unarchiveObjectWithData(notificationData) as! UILocalNotification
firedNotificationsToReturn.append(notificationToAdd)
}
return firedNotificationsToReturn
} catch {
return nil
}
}
Note that this returns an array of UILocalNotifications.
When retrieving these if you plan on removing a few of them and then storing the list again you should remove them when you get them something like this works:
func loadFiredNotifications() {
let notifications = StudyHelper().getLocalFiredNotifications()
if notifications != nil {
firedNotifications = notifications!
} else {
// throw an error or log it
}
classThatRemoveMethodIsIn().removeFiredLocalNotifications()
}
I hope this helps someone who had the same problems that I did trying to implement this.

Swift Optional Binding with a negative result

How can I do an optional binding in Swift and check for a negative result? Say for example I have an optional view controller that I'd like to lazy load. When it's time to use it, I'd like to check if it's nil, and initialize it if it hasn't been done yet.
I can do something like this:
if let vc = viewController? {
// do something with it
} else {
// initialize it
// do something with it
}
But this is kludgey and inefficient, and requires me to put the "do something with it" code in there twice or bury it in a closure. The obvious way to improve on this from objC experience would be something like this:
if !(let vc = viewController?) {
// initialize it
}
if let vc = viewController? {
// do something with it
}
But this nets you a "Pattern variable binding cannot appear in an expression" error, which is telling me not to put the binding inside the parenthesis and try to evaluate it as an expression, which of course is exactly what I'm trying to do...
Or another way to write that out that actually works is:
if let vc = viewController? {
} else {
// initialize it
}
if let vc = viewController? {
// do something with it
}
But this is... silly... for lack of a better word. There must be a better way!
How can I do an optional binding and check for a negative result as the default? Surely this is a common use case?
you can implicitly cast Optional to boolean value
if !viewController {
viewController = // something
}
let vc = viewController! // you know it must be non-nil
vc.doSomething()
Update: In Xcode6-beta5, Optional no longer conform to LogicValue/BooleanType, you have to check it with nil using == or !=
if viewController == nil {
viewController = // something
}
Would this work for you?
if viewController == nil {
// initialize it
}
// do something with it
One way might be to create a defer statement that handles the actions. We can ensure those actions occur after the creation of our object by checking for nil. If we run into nil, instantiate the object and return. Before returning our deference will occur within the scope of some function.
func recreateAndUse() {
defer {
viewController?.view.addSubview(UIView())
viewController!.beginAppearanceTransition(true, animated: true)
}
guard viewController != nil else {
viewController = UIViewController()
return
}
}

Swift bad execution when checking length

I am trying to evaluate the contents of a form field that, when empty is throwing an error.
Here is the outlet code
#IBOutlet var txtUsername : UITextField!
Here is the println for the target field.
println("\(txtUsername)")
<UITextField: 0x10e8280a0; frame = (20 40; 280 30); text = ''; clipsToBounds = YES; opaque = NO; autoresize = RM+BM; gestureRecognizers = <NSArray: 0x10e828b20>; layer = <CALayer: 0x10e828300>>
So, looking at this I would assume that txtUsername.text is empty or == "". But everything I try to do to evaluate this throws an error.
if countElements(txtUsername.text as String) != 0 {
... code here
}
if txtUsername.text.bridgeToObjectiveC().length != 0 {
... code here
}
if txtUsername.text.utf16count != 0 {
... code here
}
if txtUsername.text != "" {
... code here
}
All bring back "EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
Also, evaluating whether it is nil doesn't seem to work. The below scripts show that there is something to be evaluated, even though it is blank. The problem is telling whether or not it is blank.
If the field was nil, I would expect it to return false and trigger the else statement.
if let evalText = txtUsername.text{
println("There is something here : \(evalText)")
} else {
println("text is nil")
}
// This returns "There is something here:"
if txtUsername.text{
println("There is something here")
} else {
println("text is nil")
}
// This returns "There is something here"
I have even tried to set the value in a variable, only to have it kick out the error after hitting the "if" statement.
Thanks,
EXC_BAD_INSTRUCTION implies an assertion failure. This is most common when something is nil but you are still trying to operate on it.
The text property of UITextField is an Implicitly Unwrapped Optional (String!). You must first check if it is nil. Your app is crashing because it is nil.
txtUsername.text is an optional in Swift. Even your label is an optional so it's not really safe to use ! when declaring it. But anyway, try using this:
if let currentText = txtUsername.text {
// ... Do something with currentText ...
}
else {
NSLog("Text is nil")
}
To be extra sure you can even check if txtUsername is set in the same way. So in the end you will have this:
if let currentTxtUsername = txtUsername{
if let currentText = currentTxtUsername.text {
// ... Do something with currentText ...
}
else {
NSLog("Text is nil")
}
}
else {
NSLog("Text label is nil")
}
Don't forget to remove the ! in the declaration part though.
Turned out to be an error ghosting issue.
The actual problem was that it would get further down in the code and run into a situation where I was inadvertently trying to put nil data from a core data object back into the text string. Setting a text field to nil doesn't work, but rather than error where the problem was, it erred at the "if" statement 20 lines above it.
Below is the full code, and some description of the issue.
#IBAction func btnLoad(sender : AnyObject) {
var appDel = (UIApplication.sharedApplication().delegate as AppDelegate)
var context = appDel.managedObjectContext
var request = NSFetchRequest(entityName: "Users")
request.returnsObjectsAsFaults = false
// Here is the place where it throws the error.
if txtUsername.text == "" {
request.predicate = NSPredicate(format: "username = %#", "\(txtUsername.text)")
}
var results = context.executeFetchRequest(request, error: nil)
println(results)
if(results.count > 0){
var res = results[0] as NSManagedObject
println("\(res)")
//*** The database had nil values for the result selected. And nil doesn't go into a text field.
txtUsername.text = res.valueForKey("username") as String
txtPassword.text = res.valueForKey("password") as String
responseLabel("User Found")
} else {
responseLabel("No Users Found")
}
}
Thanks everyone for replying.