-1

I use delegation in Swift on a regular basis and have implemented it successfully on a number of projects. I am currently having an issue I don't understand. After my CreateMessageBEDelegate delegate fires the call back method, the CreateMessageBE object is nil in MessageViewController. When testing the message object in CreateMessageBE prior to the call back I can see that it is not nil.

The info below is a walk through of the code. Any idea why this is not working?

UPDATED Specific Problem - createMessageBE is nil, see not below.

func createMessageBEWithMessageSenderAndMessageReceiverDidSuceed(createMessageBEInput: CreateMessageBE)
    {
        self.message = self.createMessageBE?.message  // createMessageBE is nil

        // Update Backendless
        self.updateBackendless = UpdateBackendless(messageBEWithMessageSenderAndMessageReceiver: self.message!, delegateInput: self)
    }

MessageViewController

class MessageViewController : UIViewController, FindMessageSenderDelegate, FindMessageReceiverDelegate, CreateMessageBEDelegate, UpdateBackendlessDelegate
{
    // Backendless Property
    let backendless = Backendless.sharedInstance()

    // Message Properties
    var messageSender : BackendlessUser?
    var MessageReceiver : BackendlessUser?
    var messageText : String?
    var message : MessageBE?

    var findMessageSender : FindMessageSender?
    var findMessageReceiver : FindMessageReceiver?
    var createMessageBE : CreateMessageBE?
    var updateBackendless : UpdateBackendless?

func findMessageReceiverDidFindUsernameMessageReceiver(findMessageReceiverInput : FindMessageReceiver)
    {
        // Set the Message User Message Receiver
        self.messageReceiver = self.findMessageReceiver!.messageReceiver

        self.createMessageBE = CreateMessageBE(guestMessageUserInput: self.guestMessageUser!, messageReceiverInput: self.messageReceiver!, messageInput: self.message!, delegateInput: self)
        //print(self.createMessageBE)  If I call this here self.createMessage is not nil in the delegate call back.  If I do not call it, it is nil.
    }

func createMessageBEWithMessageSenderAndMessageReceiverDidSuceed(createMessageBEInput: CreateMessageBE)
    {
        // Set the MessageBE Property
        self.message = self.createMessageBE?.message

        // Update Backendless
        self.updateBackendless = UpdateBackendless(messageBEWithMessageSenderAndMessageReceiver: self.message!, delegateInput: self)
    }

Here is the CreateMessageBE class

import Foundation
import CoreData

protocol CreateMessageBEDelegate
{
    func createMessageBEWithMessageSenderAndMessageReceiverDidSuceed(createMessageBEInput : CreateMessageBE) -> ()
}

class CreateMessageBE : NSObject
{
    // Properties
    var message : MessageBE?

    // Backendless Property
    let backendless = Backendless.sharedInstance()

    // Delegate Property
    var delegate : CreateMessageBEDelegate?

    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    // Custom Init Method
    init(messageSenderInput: BackendlessUser, messageReceiverInput: BackendlessUser, messageTextInput: String, delegateInput: CreateMessageBEDelegate)
    {
        super.init()

        // Create MessageBE for Message User Sender and Message User Receiver
        self.message = MessageBE(messageSenderInput: messageSenderInput, messageReceiverInput: messageReceiverInput, messageTextInput: messageTextInput)
        self.delegate = delegateInput

        self.returnMessageBEWithMessageSenderAndMessageReceiver()
    }
    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    func returnMessageBEWithMessageSenderAndMessageReceiver()
    {
        // Return the created MessageBE to MessageViewController
        if self.message != nil
        {
            print("In the createMessageBEDelegate and printing self.message \(self.message)")
            self.delegate?.createMessageBEWithMessageSenderAndMessageReceiverDidSuceed(self)
        }
        else
        {
            // Report error.
        }
    }
}

Here is the MessageBE class

import Foundation
import UIKit

class MessageBE: NSObject
{
    // This is a custom class used to access Message Objects that are stored Backendless.
    var objectId : String?
    var created : NSDate?
    var updated : NSDate?
    var messageSender : BackendlessUser?
    var messageReceiver : BackendlessUser?
    var messageText : String?
    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    init(messageSenderInput: BackendlessUser, messageReceiverInput: BackendlessUser, messageTextInput: Double)
    {
        self.messageSender = messageSenderInput
        self.messageReceiver = messageReceiverInput
        self.messageText = messageTextInput
    }
}
jonthornham
  • 2,881
  • 4
  • 19
  • 35
  • Don't force-unwrap your optionals, and you won't have issues like this. – Crowman Aug 27 '16 at 01:44
  • That's a lot of code. I can't figure out what the question is or how it relateds to all that code. Could you reduce it to a few lines that show clearly and exactly what the problem is and where it occurs? – matt Aug 27 '16 at 02:57
  • I just added a code block at the top that shows where createMessageBE is nil. – jonthornham Aug 27 '16 at 03:31
  • If I do not force unwrap it gives me an error. Am I missing something? – jonthornham Aug 27 '16 at 03:31
  • @jonthornham: Yes, you're missing how to use optionals properly. – Crowman Aug 27 '16 at 03:36
  • @PaulGriffiths Ok, thanks. Swift docs? Is it something you can point out quickly? – jonthornham Aug 27 '16 at 03:44
  • @jonthornham: Any decent Swift tutorial should cover it. Apple's "The Swift Programming Language" is free and is the obvious choice. – Crowman Aug 27 '16 at 03:46
  • @PaulGriffiths I've been reading all morning on optionals. Since self.message is defined as an optional, I have to unwrap it at some point. I test in the delegate to see if it is non nil. When I pass it back to the MessageViewController is is nil if I test it. I understand an optional means it contains a value or it doesn't. What I don't understand is why it contains a value int he delegate but not in the MessageViewController. What am I missing? – jonthornham Aug 27 '16 at 19:56
  • @jonthornham: Just the overall approach to using optionals. If you declare a property to be an optional, you are stating that it is something legitimate for it to be `nil`. Therefore, you should always be prepared to handle this case, but you don't, you force unwrap it. It contradicts your assertion that it's expected to be sometimes `nil`. In `CreateMessageBE`, you define `message` as an optional, but set it in the initializer and never change it. So why is it an optional? Make it non-optional, and it'll never be `nil`. These are the kinds of things you need to be thinking about. – Crowman Aug 27 '16 at 20:02
  • Similarly, `message` and `delegate` should be non-optional constants, not optional variables, since you set them on initializer with a non-optional value, and then never change them. You seem to be working against the language, instead of with it. The types you choose appear not to match your intent, and so it's difficult for you to reason about what your program is doing. With this type of error that's confusing you, Swift gives you the ability to stop them ever arising, but you're not taking advantage of that ability. – Crowman Aug 27 '16 at 20:15
  • @PaulGriffiths I have more homework to do. I'm not there yet but I'll see what I can do to figure it out. Thanks for the help. – jonthornham Aug 27 '16 at 20:21

1 Answers1

0

I figured out the issue with my code. It the problem was that I was trying to access self.createMessageBE in the delegate call back before the instantiation of self.createMessageBE was complete. The order and placement of my methods was wrong. Below I show the initial code and then the new updated code.

You can see that the placement of the call returnMessageBEWithMessageSenderAndMessageReceiver() is what makes the difference. With this call in the correct location, self.createMessageBE is not nil since it's been instantiated. I hope this helps someone else.

MessageViewController Class

Original Code

    func findMessageReceiverDidFindUsernameMessageReceiver(findMessageReceiverInput : FindMessageReceiver)
        {
            // Set the Message User Message Receiver
            self.messageReceiver = self.findMessageReceiver!.messageReceiver

            // Create createMessageBE
            self.createMessageBE = CreateMessageBE(guestMessageUserInput: self.guestMessageUser!, messageReceiverInput: self.messageReceiver!, messageInput: self.message!, delegateInput: self)     
        }

New Code

func findMessageReceiverDidFindUsernameMessageReceiver(findMessageReceiverInput : FindMessageReceiver)
    {
        // Set the Message User Message Receiver
        self.messageReceiver = self.findMessageReceiver!.messageReceiver

        self.createMessageBE = CreateMessageBE(guestMessageUserInput: self.guestMessageUser!, messageReceiverInput: self.messageReceiver!, messageInput: self.message!, delegateInput: self)
        self.createMessageBE?.returnMessageBEWithMessageSenderAndMessageReceiver()
    }

CreateMessageBE Class

Original Code

// Custom Init Method
    init(messageSenderInput: BackendlessUser, messageReceiverInput: BackendlessUser, messageTextInput: String, delegateInput: CreateMessageBEDelegate)
    {
        super.init()

        // Create MessageBE for Message User Sender and Message User Receiver
        self.message = MessageBE(messageSenderInput: messageSenderInput, messageReceiverInput: messageReceiverInput, messageTextInput: messageTextInput)
        self.delegate = delegateInput

        self.returnMessageBEWithMessageSenderAndMessageReceiver()
    }

New Code

// Custom Init Method
    init(messageSenderInput: BackendlessUser, messageReceiverInput: BackendlessUser, messageTextInput: String, delegateInput: CreateMessageBEDelegate)
    {
        super.init()

        // Create MessageBE for Message User Sender and Message User Receiver
        self.message = MessageBE(messageSenderInput: messageSenderInput, messageReceiverInput: messageReceiverInput, messageTextInput: messageTextInput)
        self.delegate = delegateInput
    }
jonthornham
  • 2,881
  • 4
  • 19
  • 35