I have a TEST table that appears to be behaving just weird. It simply consists of two integers, ID (auto increment) and LOCATIONSELECTED.
The table is populated
1, 99
2, 100
3, 101
etc
If I try and find LOCATIONSELECTED using the code below it works and returns 99!
func getTestSelectedRecord() {
sharedInstance.database!.open()
var sqlStatement = "SELECT * FROM TEST WHERE ID = 1"
var resultSet: FMResultSet! = sharedInstance.database!.executeQuery(sqlStatement, withArgumentsInArray: nil)
if (resultSet != nil) {
while resultSet.next() {
let getRecordID = resultSet.intForColumn("LOCATIONSELECTED")
NSLog("DatabaseFunctions - TEST - GET - getRecordID = %i", getRecordID)
}
}
sharedInstance.database!.close()
}
But if I remove the while loop it returns nul. I normally write my SELECT calls without the if != nil and while calls at all. There is only one record with an ID of 1 in the table.
I presume something subtle is going on here. Can anyone explain what it is?
You can remove the while loop, but you must maintain the:
resultSet.next();
statement, since is this the operation that allows to access the first (and only) record of the result.
Related
I need to fetch from Realm Results 20 objects or less. A database can be heavy, so Results.count is a long time for calling.
So, what I need is to fetch objects from Results one by one until I get 20 or until last object.
But, when I'm trying to fetch index after the last object it's throwing Realm exception 'Index x is out of bounds (must be less than x)'.
So, this one isn't working:
let searchResult = Ticket().get(filter: "base == nil && deleted == 0 AND orderPaidAt > 0 AND (\(query))").sorted(byKeyPath: "orderPaidAt")
for i in 0..<20 {
if let ticket = searchResult[i] as? Ticket {
...
} else {
break
}
}
If I'm trying to use searchResult.count or searchResult.endIndex it increases a time a lot, especially on old devices. That's why I want to avoid it.
The results are lazily loaded, so you could loop through the results one by one, until the end, or until you hit a self-set count:
let searchResult = Ticket().get(filter: "base == nil && deleted == 0 AND orderPaidAt > 0 AND (\(query))").sorted(byKeyPath: "orderPaidAt")
var count = 0
for thisTicket in searchResult {
// do something
count += 1
if count > 20 { break }
}
This way you are only loading the values that you need, and never calling count or accessing the results out of bounds.
You can use prefix(maxLenght: Int) method to get a subCollection with specified maxLenght.
Example:
realm.objects(ObjectModel.self).prefix(20).count
How can I check the last row in this loop below. Im using SQlite.swift in order to cycle through all the rows in the table. When I hit the last row, I want to do something.
for data in try dbConnection.prepare(tableName) {
if (thisIsTheLastRow) {
//do something
}
}
Here is the library reference but I couldent find anything about getting specific indexes through the loop
You could either do a for index loop:
let count = try! db.scalar("SELECT count(*) FROM Table") as! Int64
for (index, data) in stmt.enumerated() {
if index == Int(count) {
// Last row
}
}
Or you could in that library make an sqlite statement and get the last row immediately:
func lastRowForTable() -> Data {
let data = try! db.scalar("SELECT * FROM table ORDER BY column DESC LIMIT 1;")
return data
}
SQLite computes result rows on demand. So there is no way to find out whether the current row is the last one except by trying to stepping to the next one.
You have to load all rows before looping over them, or do the "do something" after the loop.
I am trying to get my app to perform functions. I have two attributes per item (quantity and price) that I want to multiply together and then total for all the didSelectRow items on the list. There is two sections on my tableView. Section 0 is regular and moved to section 1 with didSelectRow. (I only explain this because it comes into play further down)
My code so far is...
`func cartTotalFunc() {
itemFetchRequest().returnsObjectsAsFaults = false
do {
let results = try moc.executeFetchRequest(itemFetchRequest())
print("===\(results)")
// Calculate the grand total.
var grandTotal = 0
for order in results {
let SLP = order.valueForKey("slprice") as! Int
let SLQ = order.valueForKey("slqty") as! Int
grandTotal += SLP * SLQ
}
print("\(grandTotal)")
cartTotal.text = "$\(grandTotal)" as String
} catch let error as NSError {
print(error)
}
}
`
slprice and slqty are strings in Core Data. I am trying to cast them as Int so they will do the arithmetic. I had this working but it totaled every item instead of only the crossed off ones (section 1). I gave it a rest for a while and now when I come back to try to work on it again Xcode is giving me an error of, "can not Could not cast value of type 'NSTaggedPointerString' (0x104592ae8) to 'NSNumber' (0x1051642a0)."
Can anyone help with this, please?
I've setup a table to pull data from a database. The user can manually delete items from the table (and thus the database) via checkbox (table.editing = true, iirc) and a delete button. This can be done one at a time, or all at a time.
Unfortunately, whenever I check everything for deletion, the app crashes with the following error:
fatal error: Array index out of range
This does not happen if I select and delete only one or any number of the table rows, as long as I don't select everything.
Here's my code for the delete button:
func deleteButtonPressed(sender: AnyObject) {
if (self.pureSteamFormView.tableCalibration.editing == true) {
if (self.pureSteamFormView.tableCalibration.indexPathsForSelectedRows!.count >= 1) {
for indexPath in self.pureSteamFormView.tableCalibration.indexPathsForSelectedRows!.sort({ $0.row < $1.row}) {
let calibTable : FormSteamPurityCalibration = self.steamPurityCalibrationTableList[indexPath.row] /* <--- ERROR HERE */
DatabaseManager.getInstance().deleteData("FormSteamPurityCalibration", "ID = \(calibTable.ID)")
self.steamPurityCalibrationTableList.removeAtIndex(indexPath.row)
}
self.pureSteamFormView?.tableCalibration.reloadData()
}
}
}
Near as I can figure, it is attempting to remove the row at an index, an index that may no longer exist (?) due to the previous row also being deleted, but I'm not sure about that.
I tried putting the following code:
self.steamPurityCalibrationTableList.removeAtIndex(indexPath.row)
In its own for-loop block, and the error promptly move there.
I also tried removing the removeAtIndex part completely, relying on the reloadData() to perhaps update the table automatically, but it doesn't work - the data is deleted from the database, but remains on the table (although moving away from that view and going back there updates the table).
Any suggestions please? Thanks.
Your problem here is that you are deleting the lowest indexes before the bigger ones. Let me explain with an example:
Image you have 4 elements in your array:
let array = ["Element1", "Element2", "Element3", "Element4"]
You are trying to remove the elements at index 1 et 3:
for index in [1, 3] {
array.removeAtIndex(index)
}
Your program will first remove element at index 1, leaving you with the following array:
["Element1", "Element3", "Element4"]
On the second pass of the loop it will try to remove the element at index 3. Which does not exist anymore because it has moved to index 2.
One solution to this is to start removing element with the greater index before, so in your code you could change
for indexPath in self.pureSteamFormView.tableCalibration.indexPathsForSelectedRows!.sort({ $0.row < $1.row}) {
to
for indexPath in self.pureSteamFormView.tableCalibration.indexPathsForSelectedRows!.sort({ $0.row > $1.row}) {
A better solution would be to filter your data array to include only the elements you whish to keep, so instead of:
for indexPath in self.pureSteamFormView.tableCalibration.indexPathsForSelectedRows!.sort({ $0.row < $1.row}) {
let calibTable : FormSteamPurityCalibration = self.steamPurityCalibrationTableList[indexPath.row]
DatabaseManager.getInstance().deleteData("FormSteamPurityCalibration", "ID = \(calibTable.ID)")
self.steamPurityCalibrationTableList.removeAtIndex(indexPath.row)
}
you could do:
self.steamPurityCalibrationTableList.filter {
if let index = self.steamPurityCalibrationTableList.indexOf ({ $0 })
{
for indexPath in self.pureSteamFormView.tableCalibration.indexPathsForSelectedRows! {
if indexPath.row == index { return false }
}
return true
}
}
I'm building a sort of hot or not style app in Swift where the user can vote: HOT, NOT and MAYBE on an image, respectively.
For every time the user gets to a image, they vote and then for each respective vote the IBAction triggers a query that shows the result of the total votes and total hots from Parse as shown in my code below.
I plan to have 1,000 images.
Can I preload all the objectIDs that correspond to each respective image and then when the user votes on the image, the data is already preloaded/queried from parse? How would i go about that?
For now, I'm writing a query for each ObjectID which would take 1000 queries from 1000 different images... Obviously unscalable.
The swipePosition variable is just a counter that counts which image the user is on. The images being stored are in an Array for now stored on Xcode. Maybe they can be preloaded as well if they are stored on Parse?
(I am only showing the "hotButtonQuery" function, but there is also a Not and Maybe buttonQuery function...)
Is there a way to simply this code so that it's scalable? Because as of now there's no way I can scale past 25 images...
Thanks a lot!
func hotButtonQuery() {
if swipePosition == 0 {
var query = PFQuery(className:"UserData")
query.getObjectInBackgroundWithId("RlvK3GhfqE") {
(userData: PFObject!, error: NSError!) -> Void in
if error != nil {
println(error)
}
else {
userData.incrementKey("totalVotes", byAmount: 1)
userData.incrementKey("hot", byAmount: 1)
var updateTotalVotesUILabel = userData.objectForKey("totalVotes") as NSInteger
var updateHotsUILabel = userData.objectForKey("hot") as NSInteger
userData.saveInBackground()
println("parse was updated!")
self.totalVotesLabel.text = String(updateTotalVotesUILabel)
self.totalHotsLabel.text = String(updateHotsUILabel)
}
}
} else if swipePosition == 1 {
var query = PFQuery(className:"UserData")
query.getObjectInBackgroundWithId("30WlVtgurP") {
(userData: PFObject!, error: NSError!) -> Void in
if error != nil {
println(error)
}
else {
userData.incrementKey("totalVotes", byAmount: 1)
userData.incrementKey("hot", byAmount: 1)
var updateTotalVotesUILabel = userData.objectForKey("totalVotes") as NSInteger
var updateHotsUILabel = userData.objectForKey("hot") as NSInteger
//println(userData.objectForKey("totalVotes"))
//println("total HOTs:")
//println(userData.objectForKey("hot"))
userData.saveInBackground()
println("parse was updated!")
self.totalVotesLabel.text = String(updateTotalVotesUILabel)
self.totalHotsLabel.text = String(updateHotsUILabel)
}
}
} else if swipePosition == 3 {
var query = PFQuery(className:"UserData")
query.getObjectInBackgroundWithId("5D6ARjk3xS") {
(userData: PFObject!, error: NSError!) -> Void in
if error != nil {
println(error)
}
else {
userData.incrementKey("totalVotes", byAmount: 1)
userData.incrementKey("hot", byAmount: 1)
var updateTotalVotesUILabel = userData.objectForKey("totalVotes") as NSInteger
var updateHotsUILabel = userData.objectForKey("hot") as NSInteger
//println(userData.objectForKey("totalVotes"))
//println("total HOTs:")
//println(userData.objectForKey("hot"))
userData.saveInBackground()
println("parse was updated!")
self.totalVotesLabel.text = String(updateTotalVotesUILabel)
self.totalHotsLabel.text = String(updateHotsUILabel)
}
}
}
Respectfully, I would suggest rethinking your whole approach. Don't store objectIds in your code. Don't repeat essentially the same block of code over and over. Keep it simple:
Retrieve and display image
Capture vote and save object
Query for next object and repeat process
If you want to reduce the number of queries, grab them in batches of 10 or so. No sense loading everything since the user is not likely to click through all 1000.
The only thing left to figure out is how you will be keeping track of which images the user has already voted on. You could do this client-side or within Parse. There are a few decent approaches.