How to use Parse.com objects? - swift

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
}

Related

JSQMessagesviewcontroller can't perform segues

so I created a chat view controller using the JSQMessagesViewController following this tutorial here: https://learnappmaking.com/chat-app-ios-firebase-swift-xcode/#comment-1930 my code is more or less the same, I didn't tweak anything significant in it, the tutorial is only for a single view controller so I added another view controllers for the app but every time it perform segues, I get the error SIGABRT, no matter if I segues with performSegue or with the back button in navigation bar, it keeps giving signal SIGABRT. any help would be appreciated.
this is my viewdidload:
override func viewDidLoad() {
super.viewDidLoad()
senderId = "1111"
senderDisplayName = "Bob"
title = "Steve"
inputToolbar.contentView.leftBarButtonItem = nil
collectionView.collectionViewLayout.incomingAvatarViewSize = CGSize.zero
collectionView.collectionViewLayout.outgoingAvatarViewSize = CGSize.zero
let query = Constants.refs.databaseChats.queryLimited(toLast: 10)
_ = query.observe(.childAdded, with: { [weak self] snapshot in
if let data = snapshot.value as? [String: String],
let id = data["sender_id"],
let name = data["name"],
let text = data["text"],
!text.isEmpty
{
if let message = JSQMessage(senderId: id, displayName: name, text: text)
{
self?.messages.append(message)
self?.finishReceivingMessage()
}
}
})
// Do any additional setup after loading the view.
}
SIGABRT (signal abort) is typically from a referencing error in your storyboard. Did you ever change the name of a class or make a connection from a button of one view controller to another and then delete it? If you changed the name of a class you must make the sure the name in the code of the class matches that. If you deleted a button connection between view controllers, click on the controller itself and under the connections tab you must delete it.

Get variable value or run function from different Object - Swift

I am trying to: get the value of a few variables, as well as run some functions which live in Object A, all from Object B.
I have tried for hours now to make it work with delegates and protocols. No luck.
I can't do something like this:
var delegate: MyDelegate = ViewController()
Because it seems to create a new instance of ViewController. And I want the values from the instance that is already running.
I also cannot do:
var delegate: MyDelegate?
Because the ViewController object never responds. So I get a nil anytime I call delegate?.somefunction()
I don't want a segue between screens. I just need to start a function from another object.
I bet this is an easy fix. I just can't get it. Thanks for your help.
Some of my code:
class PauseButtonView: NSView{
var delegate: PauseButtonDelegate?
...
var result = delegate?.startFunction()
}
protocol PauseButtonDelegate {
func startFunction() -> String
}
class ViewController: NSViewController, PauseButtonDelegate {
func startFunction() -> String {
let myString = "Hello World!"
return myString
}
}
If you don't want either classes to have a reference to the other, you could use internal notifications to communicate between them:
// in your PauseButtonView
let object:[String:AnyObject] = [ "aParameter" : 42 ]
let startNotification = NSNotification(name: "startFunction:", object: object)
NSNotificationCenter.defaultCenter().postNotification(startNotification)
// in the view controller
func startFunction(notification:NSNotification)
{
let object = notification.object as? [String:AnyObject]
//...
}

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()
}
}
}
}

Using a UIViewController as the default value for an optional parameter, but I get the "X does not have a member named Y" error

So I have been having fun with default parameter values.
class containerViewController: UIViewController {
var detailView:UIViewController?
override func viewDidLoad(){
super.viewDidLoad()
detailView = anotherViewController()
}
func hideDetailView(vc:UIViewController? = detailView){ // <- THIS LINE
// code
}
}
The line Ive marked produces an error:
'containerViewController.Type' does not have a member named 'detailView'
Ive been reading online, including this question, but I cant seem to figure out how to fix this.
What I want is to be able to use hideDetailView() and if I send in a specific view controller as a parameter to that function, it hides that specific view controller. If I dont send any parameter, it just hides the current view controller that is held in the detailView parameter.
How can I achieve this?
You can use nil for the default value, and check if nil in the body.
func hideDetailView(vc:UIViewController? = nil){ // <- THIS LINE
let vc_ = vc ?? detailView
// code
}
But In this case, you can't distinguish following calls:
// passing `nil` as Optional<UIViewController>
let vc:UIViewController? = nil
container.hideDetailView(vc: vc)
// use default value
container.hideDetailView()
If you don't like that, you can use UIViewController??:
func hideDetailView(vc:UIViewController?? = nil){
let vc_ /*: UIViewController? */ = vc ?? detailView
// code
}

error "secondViewController does not have a member named "mastername"

I am using a sample from IOS 8 App Development Essentials. I added a variable to my second controller but keep getting this error.
Second controller code:
Class SocondDetailController: UIViewController{
var mastername: String?
...
}
First controller code:
override func prepareForSegue(segue: UIStoryboardSegue,sender: AnyObject?)
{
if segue.identifier == "ShowDetails"
{        
let detailViewController = segue.destinationViewController as SocondDetailController
let myIndexPath = self.tableView.indexPathForSelectedRow()
let row = myIndexPath?.row
SocondDetailController.mastername = tableData[row!]
}
}
I am new to Swift and IOS development. Just starting at age 71.
I have been using VB.Net for a long time.
Please help.
Thanks.
This row:
SocondDetailController.mastername = tableData[row!]
should be:
detailViewController.mastername = tableData[row!]
mastername is an instance property, and as such you have to access to it through an instance of SocondDetailController, and not the SocondDetailController type itself.
Also, although probably not needed due to the logic in your view controller, I'd avoid using the forced unwrapping operator !, preferring a safer optional binding:
let row = myIndexPath?.row
if let row = row {
detailViewController.mastername = tableData[row]
}
or, more concisely:
if let row = myIndexPath?.row {
detailViewController.mastername = tableData[row]
}