Can not querying from CoreData in swift 3 - xcode

I'm using this class function to search for a record by one field. The problem here is this always returns nil, and if remove the predicate will return any row from the database. I'm using Xcode v 8.0
class func visitorWithCode(code: String, inManagedObjectContext context: NSManagedObjectContext) -> Visitor? {
print(code)
var visitor: Visitor? = nil
let fetchRequest: NSFetchRequest<Visitor> = NSFetchRequest(entityName: "Visitor")
fetchRequest.predicate = NSPredicate(format: "barcodeNo == \(code)")
fetchRequest.fetchLimit = 1
let fetchedData = try! context.fetch(fetchRequest)
if (!fetchedData.isEmpty) {
print(fetchedData.first)
visitor = fetchedData.first! as Visitor
return visitor
}
else {
return visitor
}
}

Related

How work history of web browser under the hood

I am trying to implement my own web browser history for WKWebView on iOS, but I can't implement this functionality completely, and each time I obtain trouble.
I can create a history where the user did be and then moving forward and backward inside history.
But I have next trouble, and I think it an only one of many problems on my way.
When I have a history with for example 10 elements, and then I am moving back to element number 5 and then go don't forward but try to open the new link I can't remove element 6-10 and put the new link.
I think my problem that I can't fully understand how history work inside all browsers under the hood, this is not a hard task but I am confused inside this algorithm.
My main data structure for holding history
Help me understand how to work this algorithm inside browsers or maybe exist a good theory about it?
I have solved this problem and realize the full algorithm well, the completed project available here: https://github.com/IhorYachmenov/Custom-browser-history-for-WKWebView.
Algorithm:
struct PlayerHistory {
static var shared = PlayerHistory()
var historyExist: Bool = false
var historyCurrentPosition: Int = 0
var historyLastPositionBeforeUpdatingHistory: Int!
var userHistoryKey: String!
var backPressed: Bool!
var forwardPressed: Bool!
var urlOfPlayer: String!
// Function only for first loading inside <viewDidLoad or another method from app LifeCycle>.
mutating func getUrlForFirstLoading(initURL: String, key: String) -> String {
urlOfPlayer = initURL
guard HistoryStorage.shared.getHistoryFromUserDefaults() != nil else {
updateFirstElement(key: key, url: initURL)
return initURL
}
guard HistoryStorage.shared.getHistoryFromUserDefaults()![key] != nil else {
return initURL
}
let position = HistoryStorage.shared.getHistoryFromUserDefaults()![key]!.count - 1
historyExist = true
historyCurrentPosition = position
userHistoryKey = key
let initUrlFromHistoryStorage = HistoryStorage.shared.getHistoryFromUserDefaults()![key]!.last!.url
return initUrlFromHistoryStorage
}
// Create new or update exist history, use this method indsede <decidePolicyForNavigation>.
mutating func updatePlayerHistory(backlisk: [String], key: String) {
var history = [WebViewHistory]()
for i in backlisk {
history.append(WebViewHistory(i))
}
if (historyExist == true) {
// If old history exist need compound both and then to save.
let oldHistory = HistoryStorage.shared.getHistoryFromUserDefaults()![key]
let oldAndNewHostoryTogether = oldHistory! + history
var keyValuePair = Dictionary<String, [WebViewHistory]>()
keyValuePair.updateValue(oldAndNewHostoryTogether, forKey: key)
HistoryStorage.shared.removeHistory()
HistoryStorage.shared.saveHistory(keyValuePair)
setCurrentPosition(url: backlisk.last!, key: key)
} else {
var keyValuePair = Dictionary<String, [WebViewHistory]>()
keyValuePair.updateValue(history, forKey: key)
historyExist = true
HistoryStorage.shared.removeHistory()
HistoryStorage.shared.saveHistory(keyValuePair)
setCurrentPosition(url: backlisk.last!, key: key)
}
}
// Before using this method check if result don't equals nil. Use this method for navigation beetween history
func moveThroughHistory(key: String, direction: Bool) -> String? {
guard historyExist != false else {
return nil
}
let history = HistoryStorage.shared.getHistoryFromUserDefaults()![key]!
if (direction == true) {
let index = historyCurrentPosition + 1
guard index != history.count else { return nil }
return history[index].url
} else {
let index = historyCurrentPosition - 1
guard index > 0 else { return history[0].url }
return history[index].url
}
}
// Method <setCurrentPosition> each time set position at history
mutating func setCurrentPosition(url: String, key: String) {
guard HistoryStorage.shared.getHistoryFromUserDefaults() != nil else { return }
guard HistoryStorage.shared.getHistoryFromUserDefaults()![key] != nil else { return }
let history = HistoryStorage.shared.getHistoryFromUserDefaults()![key]
let index = history?.firstIndex(of: WebViewHistory(url))
guard index != nil else {
historyCurrentPosition = 0
return
}
historyCurrentPosition = index!
}
// <removeUnusedPeaceOfHistory> need use when user want open new page staying inside the middle of history
mutating func removeUnusedPeaceOfHistory(key: String) {
guard HistoryStorage.shared.getHistoryFromUserDefaults() != nil else {
return
}
guard HistoryStorage.shared.getHistoryFromUserDefaults()![key] != nil else {
return
}
var history = HistoryStorage.shared.getHistoryFromUserDefaults()![key]!
let startIndex = historyCurrentPosition + 1
let endIndex = history.endIndex - 1
let countOfAllElements = history.count
guard startIndex != countOfAllElements else { return }
let range = startIndex...endIndex
history.removeSubrange(range)
var keyValuePair = Dictionary<String, [WebViewHistory]>()
keyValuePair.updateValue(history, forKey: key)
HistoryStorage.shared.removeHistory()
HistoryStorage.shared.saveHistory(keyValuePair)
}
// Use <updateFirstElement> inside <getUrlForFirstLoading> if history doesn't exist
private mutating func updateFirstElement(key: String, url: String) {
var history = [WebViewHistory]()
history.insert(WebViewHistory(url), at: 0)
var keyValuePair = Dictionary<String, [WebViewHistory]>()
keyValuePair.updateValue(history, forKey: key)
HistoryStorage.shared.saveHistory(keyValuePair)
historyExist = true
historyCurrentPosition = 0
}
// Use <webViewWillBeClosedSaveHistory> when WKWebView should be closed, if the user moves through history new position will be saved.
mutating func webViewWillBeClosedSaveHistory(key: String) {
let history = HistoryStorage.shared.getHistoryFromUserDefaults()![key]!
let currentPosition = historyCurrentPosition + 1
guard currentPosition != history.count else { return }
removeUnusedPeaceOfHistory(key: key)
}
}

swift 3 core data fetch results

i have a core data modal with the entity "Users"
There are two attributes "firstName" and "secondName"
this is actually my code to fetch the results:
var content:[String] = []
func RequestData() {
let appdelegate = NSApplication.shared().delegate as! AppDelegate
let context = appdelegate.persistentContainer.viewContext
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Kunden")
request.returnsObjectsAsFaults = false
do {
let results = try context.fetch(request)
if results.count > 0 {
for result in results as! [NSManagedObject] {
if let firstname = result.value(forKey: "firstname") as? String {
content.append(firstname)
}
if let secondname = result.value(forKey: "secondname") as? String {
content.append(secondname)
}
}
}
tbl_kunden.reloadData()
} catch {
print("ERROR")
}
}
this works fine.
Problem is. I dont belive that
var content:[String] = []
is the correctly variable to take the results.
Because the output of print(content) is:
["Max", "Mustermann", "Max2", "Mustermann2", "Max3", "Mustermann3"]
Which variable type will be the best for this situation?
i think the result should be something like this:
+ID
++Max
++Mustermann
+ID
++Max2
++Mustermann2
+ID
++Max3
++Mustermann3
You should create custom User objects that are subclasses of NSManagedObject.
https://developer.apple.com/reference/coredata/nsmanagedobject
But if you don't need custom logic, you could change your variable to a Int:[String] Dictionary:
var content:[Int: [String]] = [:]
And append the data like this:
if let id = result.value(forKey: "firstname") as? Int {
let firstName = result.value(forKey: "firstname") as? String ?? "Unknown"
let secondName = result.value(forKey: "secondname") as? String ?? "Unknown"
let user = [id: [firstName, lastName]]
print("Fetched user: \(user.debugDescription)")
}

Filtering array of dictionaries in Swift

I have An Array With Dictionaries example :
(
{
Email = "kate-bell#mac.com";
Name = "Kate Bell";
Number = "(555) 564-8583";
},
{
Email = "d-higgins#mac.com";
Name = "Daniel Higgins";
Number = "555-478-7672";
}
)
And i want to filter this dictionary according to Key "Name"
func searchBar(searchBar: UISearchBar, textDidChange searchText: String) {
let predicate = NSPredicate(format:"Name == %#", searchText)
let filteredArray = (arrContact as NSMutableArray).filteredArrayUsingPredicate(predicate)
print(filteredArray)
if(filteredArray.count == 0){
searchActive = false;
} else {
searchActive = true;
}
tblData.reloadData()
}
I am always getting empty array in result from above swift code. Please help me to resolve this issue. Thanks
I suggest using Swift's filter instead:
func searchBar(searchBar: UISearchBar, textDidChange searchText: String) {
let filteredArray = arrContact.filter { $0["Name"] == searchText }
print(filteredArray)
if filteredArray.isEmpty {
searchActive = false
} else {
searchActive = true
}
tblData.reloadData()
}
And as mentioned by #LeoDabus in his comment, you can even simplify further:
func searchBar(searchBar: UISearchBar, textDidChange searchText: String) {
let filteredArray = arrContact.filter { $0["Name"] == searchText }
print(filteredArray)
searchActive = !filteredArray.isEmpty
tblData.reloadData()
}
Try This for swift 3
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
// Put your key in predicate that is "Name"
let searchPredicate = NSPredicate(format: "Name CONTAINS[C] %#", searchText)
let array = (arrContact as NSArray).filtered(using: searchPredicate)
print ("array = \(array)")
if(array.count == 0){
searchActive = false;
} else {
searchActive = true;
}
self.aTable.reloadData()
}
Swift
Get list of item/array from model class.
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if self.searchBarItems.text == "" {
self.arrFilter = self.arrayDictionarySubModel
} else {
self.arrFilter.removeAll()
let filteredArray = self.arrayDictionarySubModel.filter { ($0.itemTitle?.contains(self.searchBarItems.text ?? ""))!}
print("filtered array:- ", filteredArray[0].itemTitle!)
self.arrFilter = filteredArray
}
self.searchItemTableView.reloadData()
}
where "name" is the key name
var namePredicate = NSPredicate(format: "Name like %#", String(searchText));
let searchPredicate = NSPredicate(format: "Name CONTAINS[C] %#", searchText)
arrrDict = self.arrrDict.filter { searchPredicate.evaluate(with: $0) };
you will get the result in dictionary specialy made to get contats from the phone book

How to wait for a background function to finish before calling another one in swift?

I will try to explain briefly what the situation is.
I am building a quiz app and I wanted it to work mainly using the internet, but also to work for a while when the user is disconnected. The older code I was using was made only with synchronous queries, it was taking more time than what I expected. So i decided to reformulate it.
The situation I projected is the following:
When my user selects a subject the app will synchronously get 1 question for each subsubject in order to be ready for my user click and to be faster.
After getting this first question, the app would then get another 4 (or how much is needed to complete 5) for each of the subsubjects asynchronously, while the user is occupied answering the first question that was presented to him.
Finally, the app would save the objects in the local datastore, so that the user can answer 5 questions for each subsubject when he is not connected.
Here is my code:
func getQuestionsRemotelyandSave (subsubject:String?, subject:String?, arrayOfSubsubjects:[String]?) {
self.getFromUserDefaults()
if Reachability.isConnectedToNetwork() == true {
if self.needsToGetQuestions == true {
let user = PFUser.currentUser()
var query = PFQuery(className: "Questions")
query.whereKey("answeredBy", equalTo: user)
query.whereKey("grade", equalTo: user["grade"])
if subsubject != nil && subject == nil {
query.whereKey("subsubject", equalTo: subsubject)
query.limit = 2
let array = query.findObjects()
for item in array {
let object = item as PFObject
var QuestionToPin = PFObject(className: "Questions")
QuestionToPin["Question"] = object["Question"] as String
QuestionToPin["rightAnswer"] = object ["rightAnswer"] as String
QuestionToPin["wrongAnswer1"] = object ["wrongAnswer1"] as String
QuestionToPin["wrongAnswer2"] = object ["wrongAnswer2"] as String
QuestionToPin["wrongAnswer3"] = object ["wrongAnswer3"] as String
QuestionToPin["grade"] = object["grade"] as String
QuestionToPin["subject"] = object ["subject"] as String
QuestionToPin["subsubject"] = object ["subsubject"] as String
QuestionToPin["feedback"] = object ["feedback"] as? String
QuestionToPin["shortFeedback1"] = object ["shortFeedback1"] as? String
QuestionToPin["shortFeedback2"] = object ["shortFeedback2"] as? String
QuestionToPin["shortFeedback3"] = object ["shortFeedback3"] as? String
QuestionToPin.pin()
}
query.limit = 3
query.findObjectsInBackgroundWithBlock({ (objects:[AnyObject]!, error:NSError!) -> Void in
if error == nil {
let questions = objects as [PFObject]
var QuestionsToPin = [PFObject]()
for object in questions {
var QuestionToPin = PFObject(className: "Questions")
QuestionToPin["Question"] = object["Question"] as String
QuestionToPin["rightAnswer"] = object ["rightAnswer"] as String
QuestionToPin["wrongAnswer1"] = object ["wrongAnswer1"] as String
QuestionToPin["wrongAnswer2"] = object ["wrongAnswer2"] as String
QuestionToPin["wrongAnswer3"] = object ["wrongAnswer3"] as String
QuestionToPin["grade"] = object["grade"] as String
QuestionToPin["subject"] = object ["subject"] as String
QuestionToPin["subsubject"] = object ["subsubject"] as String
QuestionToPin["feedback"] = object ["feedback"] as? String
QuestionToPin["shortFeedback1"] = object ["shortFeedback1"] as? String
QuestionToPin["shortFeedback2"] = object ["shortFeedback2"] as? String
QuestionToPin["shortFeedback3"] = object ["shortFeedback3"] as? String
QuestionToPin.pinInBackground()
}
}
})
}
if subsubject == nil && subject != nil {
var firstTime = true
var semaphore = dispatch_semaphore_create(0)
query.limit = 1
for item in arrayOfSubsubjects! {
if item != "Todas as matérias" {
var query3 = PFQuery(className: "Questions")
query3.fromLocalDatastore()
query3.whereKey("subsubject", equalTo: item)
let count = query3.countObjects()
if count == 0 {
query.whereKey("subsubject", equalTo: item)
let array:NSArray = query.findObjects()
for item in array {
let object = item as PFObject
var QuestionToPin = PFObject(className: "Questions")
QuestionToPin["Question"] = object["Question"] as String
QuestionToPin["rightAnswer"] = object ["rightAnswer"] as String
QuestionToPin["wrongAnswer1"] = object ["wrongAnswer1"] as String
QuestionToPin["wrongAnswer2"] = object ["wrongAnswer2"] as String
QuestionToPin["wrongAnswer3"] = object ["wrongAnswer3"] as String
QuestionToPin["grade"] = object["grade"] as String
QuestionToPin["subject"] = object ["subject"] as String
QuestionToPin["subsubject"] = object ["subsubject"] as String
QuestionToPin["feedback"] = object ["feedback"] as? String
QuestionToPin["shortFeedback1"] = object ["shortFeedback1"] as? String
QuestionToPin["shortFeedback2"] = object ["shortFeedback2"] as? String
QuestionToPin["shortFeedback3"] = object ["shortFeedback3"] as? String
QuestionToPin.pin()
}
}
if count > 0 {
var limit = 5 - count
if limit < 0 {
limit = 0
}
query.limit = limit
if firstTime == false {
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)
}
query.findObjectsInBackgroundWithBlock({ (objects:[AnyObject]!, error:NSError?) -> Void in
if error == nil {
let questions = objects as [PFObject]
for object in questions {
var QuestionToPin = PFObject(className: "Questions")
QuestionToPin["Question"] = object["Question"] as String
QuestionToPin["rightAnswer"] = object ["rightAnswer"] as String
QuestionToPin["wrongAnswer1"] = object ["wrongAnswer1"] as String
QuestionToPin["wrongAnswer2"] = object ["wrongAnswer2"] as String
QuestionToPin["wrongAnswer3"] = object ["wrongAnswer3"] as String
QuestionToPin["grade"] = object["grade"] as String
QuestionToPin["subject"] = object ["subject"] as String
QuestionToPin["subsubject"] = object ["subsubject"] as String
QuestionToPin["feedback"] = object ["feedback"] as? String
QuestionToPin["shortFeedback1"] = object ["shortFeedback1"] as? String
QuestionToPin["shortFeedback2"] = object ["shortFeedback2"] as? String
QuestionToPin["shortFeedback3"] = object ["shortFeedback3"] as? String
QuestionToPin.pinInBackground()
}
dispatch_semaphore_signal(semaphore)
firstTime = false
}
})
}
}
}
}
}
}
}
The problem I'm facing is that I cant request multiple asynchronous functions from Parse. What I thought was maybe waiting for an asynchronous function to finish before the other one starts, but I wanted it to happen without the user having to wait. Is there a way of doing it?
Thank you.

Replacing NSNulls inside NSDictionary

this question is similar to Replace occurrences of NSNull in nested NSDictionary
In swift I am getting an error (I believe because of NSNull's) I don't really care if the NSNull becomes an empty string or a nil. I am just wanting to get the code to work.
I have a large data structure coming in from JSON as an NSDictionary. Then I am saving that to a temporary file. Here is the code:
var jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: .MutableContainers, error: &err) as! NSDictionary
let json = JSON(jsonResult)
if (json["errors"].array?.count > 0) {
println("could not load stuff")
} else {
println("retrieving the stuff")
let file = "file.txt"
let file_path = NSTemporaryDirectory() + file
let dict:NSDictionary = jsonResult
let readDict:NSDictionary? = NSDictionary(contentsOfFile: file_path)
if dict.writeToFile(file_path, atomically: true) {
let readDict:NSDictionary? = NSDictionary(contentsOfFile: file_path)
//--- need to handle the NSNull junk here
if let dict = readDict {
println("Temp file created, here are the contents: \(dict)")
} else {
println("!!!Failed to READ the dictionary data back from disk.")
}
}
else {
println("!!!Failed to WRITE the dictionary to disk.")
}
}
Here's an example of what jsonResult looks like
things = (
{
"one" = one;
two = "<null>";
"three" = three;
"four" = "<null>";
"five" = five;
"six" = "six-6";
seven = 7;
eight = eight;
nine = "<null>";
ten = "<null>";
eleven = "<null>";
"twelve" = "<null>";
},
UPDATE:
Problem: I have a very large amount of JSON (roughly 600kb as text) Within that JSON data there are nulls. The problem I was having is that when you NSJSONSerialization as NSDictionary, it converts the nulls into NSNull objects (it looks funky if you print this out because they appear as a string, this is wrong.
Solution: You need to have a "pruned" or "sanitized" dictionary. What this means is to throw out the key and value entirely. To do this, I added a sanitized_dict function. Here is the function:
func sanitize_dict(obj: AnyObject) -> AnyObject {
if obj.isKindOfClass(NSDictionary) {
var saveableObject = obj as! NSMutableDictionary
for (key, value) in obj as! NSDictionary {
if (value.isKindOfClass(NSNull)) {
//println("Removing NSNull for: \(key)")
saveableObject.removeObjectForKey(key)
}
if (value.isKindOfClass(NSArray)) {
let tmpArray: (AnyObject) = sanitize_dict(value as! NSArray)
saveableObject.setValue(tmpArray, forKey: key as! String)
}
if (value.isKindOfClass(NSDictionary)) {
let tmpDict: (AnyObject) = sanitize_dict(value as! NSDictionary)
saveableObject.setValue(tmpDict, forKey: key as! String)
}
}
return saveableObject
//--- because arrays are handled differently,
//--- you basically need to do the same thing, but for an array
//--- if the object is an array
} else if obj.isKindOfClass(NSArray) {
var saveableObject = [AnyObject]()
for (index, ele) in enumerate(obj as! NSArray) {
if (ele.isKindOfClass(NSNull)) {
// simply don't add element to saveableobject and we're good
}
if (ele.isKindOfClass(NSArray)) {
let tmpArray: (AnyObject) = sanitize_dict(ele as! NSArray)
saveableObject.append(tmpArray)
}
if (ele.isKindOfClass(NSDictionary)) {
let tmpDict: (AnyObject) = sanitize_dict(ele as! NSDictionary)
saveableObject.append(tmpDict)
}
}
return saveableObject
}
// this shouldn't happen, but makes code work
var saveableObject = [AnyObject]()
return saveableObject
}
So your other code needs to call that function, it should look something like this:
var err: NSError?
var jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: .MutableContainers, error: &err) as! NSDictionary
//--- right now jsonResult is not actual json, and actually has the NSNulls
//--- get that result into the sanitized function above
let saveableDict: (AnyObject) = self.sanitize_dict(jsonResult)
let json = JSON(saveableDict)
if (json["errors"].array?.count > 0) {
println("!!!Failed to load.")
} else {
println("Load json successful. Attempting to save file...")
//--- set up basic structure for reading/writing temp file
let file = "file.txt"
let file_path = NSTemporaryDirectory() + file
let dict:NSDictionary = jsonResult
let readDict:NSDictionary? = NSDictionary(contentsOfFile: file_path)
if dict.writeToFile(file_path, atomically: true) {
let readDict:NSDictionary? = NSDictionary(contentsOfFile: file_path)
if let dict = readDict {
println("Temp file created, here are the contents: \(dict)")
} else {
println("!!!Failed to READ the dictionary data back from disk.")
}
}
else {
println("!!!Failed to WRITE the dictionary to disk.")
}
}
Hope this helps somebody out there with a big JSON dataset and nulls. It is all about that sanitize function!

Resources