Getting an error while loading data into WKInterfaceTable - swift

I create a watchKit app/extension of my app. I use this func to load the data into the WKInterfaceTable:
// Load table into the data
func loadTableData() {
let sharedDefault = NSUserDefaults(suiteName: "group.com.Devpr.App")
let numberItems = sharedDefault?.objectForKey("numberItems") as? Int
tableView.setNumberOfRows(numberItems!, withRowType: "Cell")
var i = 0
let task = sharedDefault?.objectForKey("\(i)WK") as? String
let row = tableView.rowControllerAtIndex(i) as! TableRowObject // Get a single row object for the current item
row.lblTblRowItem.setText(task) // Set the row text to the corresponding item
i++ // Move onto the next item
}
The app is crashing in this line of the function: let row = tableView.rowControllerAtIndex(i) as! TableRowObject with this error: fatal error: unexpectedly found nil while unwrapping an Optional value. I really can't find anything which is nil.
Image after the crash:
I hope someone of you can help me to solve this. Thanks a lot for you're help!

If numberOfItems is 0, tableView.rowControllerAtIndex(i) can be nil.

Related

Swift after iterating list.count always 0 [duplicate]

I have an array of struct called displayStruct
struct displayStruct{
let price : String!
let Description : String!
}
I am reading data from firebase and add it to my array of struct called myPost which is initialize below
var myPost:[displayStruct] = []
I made a function to add the data from the database to my array of struct like this
func addDataToPostArray(){
let databaseRef = Database.database().reference()
databaseRef.child("Post").queryOrderedByKey().observe(.childAdded, with: {
snapshot in
let snapshotValue = snapshot.value as? NSDictionary
let price = snapshotValue?["price"] as! String
let description = snapshotValue?["Description"] as! String
// print(description)
// print(price)
let postArr = displayStruct(price: price, Description: description)
self.myPost.append(postArr)
//if i print self.myPost.count i get the correct length
})
}
within this closure if I print myPost.count i get the correct length but outside this function if i print the length i get zero even thou i declare the array globally(I think)
I called this method inside viewDidLoad method
override func viewDidLoad() {
// setup after loading the view.
super.viewDidLoad()
addDataToPostArray()
print(myPeople.count) --> returns 0 for some reason
}
I want to use that length is my method below a fucntion of tableView
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return myPost.count --> returns 0
}
Any help would be greatly appreciated!
You making a asynchronous network request inside closure and compiler doesn't wait for the response, so just Reload Table when get post data. replace the code with below it work works fine for you. All the best.
func addDataToPostArray(){
let databaseRef = Database.database().reference()
databaseRef.child("Post").queryOrderedByKey().observe(.childAdded, with: {
snapshot in
let snapshotValue = snapshot.value as? NSDictionary
let price = snapshotValue?["price"] as! String
let description = snapshotValue?["Description"] as! String
// print(description)
// print(price)
let postArr = displayStruct(price: price, Description: description)
self.myPost.append(postArr)
print(self.myPost.count)
print(self.myPost)
self.tableView.reloadData()
//if i print self.myPost.count i get the correct length
})
}
Firebase observe call to the database is asynchronous which means when you are requesting for the value it might not be available as it might be in process of fetching it.
That's why your both of the queries to count returns 0 in viewDidLoad and DataSource delegeate method.
databaseRef.child("Post").queryOrderedByKey().observe(.childAdded, with: { // inside closure }
Inside the closure, the code has been already executed and so you have the values.
What you need to do is you need to reload your Datasource in main thread inside the closure.
databaseRef.child("Post").queryOrderedByKey().observe(.childAdded, with: {
// After adding to array
DispatchQueue.main.asyc {
self.tableView.reloadData()
}
}

Core Data - Change NSManagedObject array into array of Strings using valueForKey -OSX

So iv using an NSTokenField to allow data entry, the TokenField will suggest thing when the user starts typing. I want it to suggest things that are already inside core data.
To do this i have this function being called when the cell moves to superview (This is all happening inside a custom table view cell)
var subjectInformation = [NSManagedObject]()
let appDel = NSApplication.sharedApplication().delegate as! AppDelegate
let context = appDel.managedObjectContext
let fetchRequest = NSFetchRequest(entityName: "SubjectInformation")
do {
let results = try context.executeFetchRequest(fetchRequest)
subjectInformation = results as! [NSManagedObject]
} catch {
}
this returns an array of NSManagedObjects, now i want for every object in managed object get get the valueForKey("subjectName") as insert it into a array of string so that i can return that inside this token field Function
func tokenField(tokenField: NSTokenField, completionsForSubstring substring: String, indexOfToken tokenIndex: Int, indexOfSelectedItem selectedIndex: UnsafeMutablePointer<Int>) -> [AnyObject]? {
return subjectInformation //this is where is should return an array eg; ["English","Maths","Science"]
How would i do this? Thanks :)
If you properly subclassed your NSManagedObject you can use expressive Swift style filters and maps. You would cast your results array to [SubjectInformation] and
let subjectList = subjectInformation.map { $0.subjectName }
Try this:
(subjectInformation as! NSArray).valueForKeyPath("#unionOfObjects.subjectName")
This should return an array of the subjectNames of all the subjectInformation items.

How do I change a switch in CoreData using Dynamic Tables (Swift)

I have an app that I am converting from objective-c to Swift and am also changing it to use dynamic (rather than static) tables. I can load the cells with entity rows but I have been unable to figure out how to reference the UISwitch value in the #IBAction function in order to save it to CoreData.
Can anyone point me to simple example of how to do this?
In storyboard, link the UISwitch in your prototype cell to the #IBAction handler in the view controller. In the handler, determine the core data object and manipulate as desired.
Assuming you have a fetched results controller (recommended):
#IBAction didFlipSwitch(sender: UISwitch) {
let point = sender.convertPoint(CGPointZero, toView:tableView)
let indexPath = tableView.indexPathForRowAtPoint(point)
let object = fetchedResultsController.objectAtIndexPath(indexPath) as! Thing
thing.flag = sender.on
}
Addition:
Pursuant to your question: If you are not using a fetched results controller (though this is not recommended), you are presumably using an Array like [Thing]. You would replace the one line with something like:
let object = dataArray[indexPath.row] // no need to cast to Thing
Second, if you need access to other values in the cell, you can get to the cell and its elements with
let cell = tableView.cellForRowAtIndexPath(indexPath) as! CustomCell
let textToRetrieve = cell.textField?.text
However, this is not a good method, because you are getting data from your UI elements. Instead you should always store the data in your model, not in a table view row!
Thus, the proper text attribute of your Thing should already have been set by the UITextFieldDelegate implementation. (You can get the indexPath and thence the desired object in pretty much the same way as above, with convertPoint and indexPathForRowAtPoint.)
Consequently, when you flip the switch and retrieve the Core Data object as shown above, the text attribute be readily available (though you will probably not need it).
Ultimately I resolved this by using both cellForRowAtIndexPath to load the cells from my data model in my custom UITableViewController class and the following code in my custom UITableViewCell class. (Probably this is what Mundi was suggesting but if so I did not understand him.)
class CREWTableViewCell: UITableViewCell {
#IBOutlet weak var myTextView: UITextView!
#IBOutlet weak var mySwitch: UISwitch!
#IBAction func changedSwitch(sender: UISwitch) {
var newDescription = self.myTextView.text // value from cell
var newSwitchValue = self.mySwitch.on // value from cell
var fetchRequest = NSFetchRequest(entityName: "Switch")
var pred1 = NSPredicate(format: "(viewName = %#)",viewName)
var pred2 = NSPredicate(format: "(switchDescription = %#)",newDescription)
fetchRequest.predicate = NSCompoundPredicate(type: NSCompoundPredicateType.AndPredicateType, subpredicates: [pred1, pred2])
// Execute the fetch request
var error: NSError? = nil
if let fetchResults = context.executeFetchRequest(fetchRequest, error: &error) as? [Switch]
{
var recordCount = 0
recordCount = fetchResults.count
if recordCount == 1 {
var appConfig = fetchResults [0]
appConfig.switchValue = newSwitchValue
if !managedObjectContext!.save(nil) {
NSLog("Unresolved error ")
abort()
}
}
}
}

How to use Parse.com objects?

I am trying to reference parse.com variables throughout my code. I'm not 100% sure how to. Where am I going wrong?
When I do this:
message["title"] = messageTitle.text
I get the error PFObject? does not have a member named subscript
Or
messageTitle.text = self.message!.title
I get the error PFObject does not have a member named 'title'
Or
messageTitle.text = message["title"]
I get the error AnyOject is not convertible to String
To give you some background:
I have a parse backend with a Message table. I refer to the table like so:
PFObject(className: "Message")
I have a messages view controller which includes a collection view MessagesViewController.swift
I have a collection view cell class which is used to display the messages on the collection view MessageCell.swift
I have a message view controller for editing a message MessageViewController.swift
I want to be able to select a cell on the MessagesViewController which will then be used by the MessageViewController to display the selected message
I declare the local message variable:
var messages = [PFObject]()
On long press:
let storyboard = self.storyboard
let vc = storyboard!.instantiateViewControllerWithIdentifier("MessageViewController") as MessageViewController
vc.message = self.messages[self.visibleCellIndex]
navigationController?.pushViewController(vc, animated: true)
Message viewController I declare its local variable and set the textfield to be equal to the message's title
var message = PFObject?()
override func viewDidLoad() {
super.viewDidLoad()
messageTitle.text = self.message.title
}
I also want to save any changes to the message or create a new message if there isn't one already
func saveButtonPressed() {
if message == nil {
message = PFObject(className: "Message")
}
message["title"] = messageTitle.text
message.saveInBackground()
}
Then I want to be able to create a message cell by binding it to a message in cellForRowAtIndexPath
Messages viewController
cell.bindWithMessage(messages[indexPath.row])
MessageCell
var message = PFObject()
func bindWithMessage(aMessage: PFObject) {
message = aMessage
messageTitle.text = message["title"]
}
According to the error message, the problem is that message is an optional. So
message?["title"] = messageTitle.text
should help.
UPDATED
Take a look at the declaration of message:
var message = PFObject?()
Is it an optoinal? It is. Can you use the syntax message["title"] = messageTitle.text on it? No, you cannot. You need to unwrap it. The question states nowhere, that he wanted to you the syntax message.title, and I cannot read minds.
when declaring the var use:
var myItem : PFObject!
And then when you go to use it, you use optional binding:
If let mySting = myItem["key"] as? String {
label.text = myString
}

Error using subscript of optional array

When using this code:
let result: AnyObject! = hitResults[0]
I am getting the following error:
[AnyObject]? does not have a member named subscript
Containing function for context:
func handleTap(gestureRecognize: UIGestureRecognizer) {
// retrieve the SCNView
let scnView = self.view as SCNView
// check what nodes are tapped
let p = gestureRecognize.locationInView(scnView)
let hitResults = scnView.hitTest(p, options: nil)
// check that we clicked on at least one object
if hitResults?.count > 0 {
// retrieved the first clicked object
let result: AnyObject! = hitResults[0]
// get its material
let material = result.node!.geometry?.firstMaterial
// highlight it
SCNTransaction.begin()
SCNTransaction.setAnimationDuration(0.5)
// on completion - unhighlight
SCNTransaction.setCompletionBlock {
SCNTransaction.begin()
SCNTransaction.setAnimationDuration(0.5)
material?.emission.contents = UIColor.blackColor()
SCNTransaction.commit()
}
material?.emission.contents = UIColor.redColor()
SCNTransaction.commit()
}
}
Does anyone know what the issue here is?
This happens because hitTest returns an optional array, so you need to unwrap before using it.
Instead of checking that the hitResults has a count > 0, you could check that there the first object exists, and then proceed to using that object
if let firstHit = scnView.hitTest(p, options: nil)?.first {
// safely use firstHit here...
}
You can't use a subscript on an optional array. [AnyObject]? Is an optional array of type AnyObject. If you are sure that hitResults is non-nil, you can unwrap it with ! then use a subscript.
let result: AnyObject! = hitResults![0]
Since hitResults is an [AnyObject]?, you can't call subscript on it without unwrapping it first. The safest way to do this is using optional binding, like so:
// check that we clicked on at least one object
if hitResults?.count > 0 {
// retrieved the first clicked object
if let result: AnyObject = hitResults?[0] {
/* safely use result here */
}
}
Or, even better, you can use optional binding with the first property of Array which returns the first element in the array if the Array is not empty, or nil:
// check that we clicked on at least one object and retrieve it
if let result = hitResults?.first {
/* safely use result here */
}