简体   繁体   English

斯威夫特(Swift):在进行当前模态搜索后,IBOutlets为零

[英]Swift: IBOutlets are nil after a Present Modally segue

Before I begin the segue, all my outlets are not nil, and work fine. 在我开始进行测试之前,我的所有销售渠道都不为零,并且工作正常。 However, as soon as the presentation happens, the IBOutlets from the first view controller are nil and my compiler says Unexpectedly found nil while unwrapping an optional value. 但是,一旦进行演示,第一个视图控制器中的IBOutlet就会为nil,而我的编译器会说, Unexpectedly found nil while unwrapping an optional value.

I am not using any special presentation or segue, so why is this happening? 我没有使用任何特殊的演示或segue,为什么会这样呢? What code can I show you? 我可以给你看什么代码?

I have timers on the first view controller that are accessing IBOutlets in the first view controller: could this be the problem? 我在第一个视图控制器上有一些计时器正在访问第一个视图控制器中的IBOutlets:这可能是问题吗?

Update: I think my compiler thinks my second view uses the same view controller as the first, and as such all the IBOutlets are nil. 更新:我认为我的编译器认为我的第二个视图使用与第一个相同的视图控制器,因此所有IBOutlets均为零。 I think this because the method viewDidLoad is being called when I do the segue. 我认为这是因为在执行segue时会调用viewDidLoad方法。

Update: You can download my source code here: Source Code 更新:您可以在此处下载我的源代码: 源代码

Update: Here is my ViewController.swift 更新:这是我的ViewController.swift

//
//  ViewController.swift
//  SuperCommunication
//
//  Created by Jonathan Grant on 8/10/15.
//  Copyright (c) 2015 VirtuMedHealth. All rights reserved.
//

import UIKit
import Parse
import FontAwesome_swift

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UITextFieldDelegate
{
    /*Sign In*/
    let me = CurrentAccount(id: "r10010101010100101")

/*Messages and Channels*/
var selectedChannelTimer = NSTimer() //timer to check for new messages
var allChannelsTimer = NSTimer() //Timer to check for new messages in all channels
var selectedChannel: Channel?
var channelList = [Channel]()
@IBOutlet weak var channelsTableView: UITableView!

/*Top Bar*/
@IBOutlet weak var topBarPrivateChat: UIView!
@IBOutlet weak var topBarOtherChat: UIView!
@IBOutlet weak var topNameLabel: UILabel!
@IBOutlet weak var topJobLabel: UILabel!
@IBOutlet weak var topOfficeLabel: UILabel!
@IBOutlet weak var topChannelNameLabel: UILabel!
@IBOutlet weak var topTypeChannelLabel: UILabel!
@IBOutlet weak var topTypeChannelIconLabel: UILabel!
@IBOutlet weak var topNumberPeopleLabel: UILabel!
@IBOutlet weak var topVideoButton: UIButton!
@IBOutlet weak var topVoiceButton: UIButton!

/*UITextFieldDelegate*/
@IBOutlet weak var messageTextField: UITextField!
func textFieldDidBeginEditing(textField: UITextField) {    //delegate method

}

func textFieldShouldEndEditing(textField: UITextField) -> Bool {  //delegate method
    return true
}

func textFieldShouldReturn(textField: UITextField) -> Bool {   //delegate method
    //textField.resignFirstResponder()

    //check if message isn't empty
    if textField.text?.isEmpty == true {

    } else {
        let cm = ChatMessage(message: (textField.text)!, dateSent: NSDate(), userSent: CurrentAccount.user!)
        chatMessages.append(cm)
        //send this message
        sendParseChatMessageObject(cm)
        textField.text = ""
        //reload table data
        tableView.reloadData()
    }

    return true
}

/*UITableViewDataSource*/
@IBOutlet weak var tableView: UITableView!
var chatMessages = [ChatMessage]()
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    //code
    if tableView.tag == 1 {
        //then they chose a message
    } else if tableView.tag == 2 {
        //then they chose a channel
        if indexPath.section == 0 {
            //then its easy
            selectedChannel = channelList[indexPath.row]
        } else if indexPath.section == 1 {
            selectedChannel = channelList[indexPath.row + Channel.publicChannels]
        } else {
            //private channel
            selectedChannel = channelList[indexPath.row + Channel.publicChannels + Channel.groupChannels]
        }
        loadMessagesForSelectedChannel()
        if selectedChannel!.tag == 3 {
            setUpTopBarForPrivateChatLabels()
        } else {
            setUpTopBarForOtherChatLabels()
        }
    }
}

func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    if tableView.tag == 1 {
        return ""
    } else {
        if tableView.tag == 2 {
            if section == 0 {
                return "Public (\(Channel.publicChannels))"
            } else if section == 1 {
                return "Group (\(Channel.groupChannels))"
            } else {
                return "Private (\(CurrentAccount.friends.count))"
            }
        }
    }
    return ""
}

func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    if tableView.tag == 1 {
        return 1
    } else if tableView.tag == 2 {
        return 3
    }
    return 1
}

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    if tableView.tag == 1 {
        return chatMessages.count
    } else if tableView.tag == 2 {
        //return amount of tags for that section
        if section == 0 {
            return Channel.publicChannels
        } else if section == 1 {
            return Channel.groupChannels
        } else {
            return CurrentAccount.friends.count
        }
    }
    return 1
}

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    if tableView.tag == 1 {
        let today = NSDate()
        let form = NSDateFormatter()
        form.dateStyle = NSDateFormatterStyle.LongStyle
        form.timeStyle = NSDateFormatterStyle.NoStyle
        if form.stringFromDate(today) == form.stringFromDate(chatMessages[indexPath.item].dateSent!) {
            //then it is today
            var identifier = "chatBox"
            print("\(chatMessages[indexPath.item].userSent!.userID) ~ \(CurrentAccount.user!.userID)")
            if chatMessages[indexPath.item].userSent!.userID == CurrentAccount.user!.userID {
                identifier = "chatBoxMe"
                print("Heuh")
            }
            let cell = tableView.dequeueReusableCellWithIdentifier(identifier, forIndexPath: indexPath) as! ChatMessageTableViewCell

            cell.configureCellWithChatMessage(chatMessages[indexPath.row])

            return cell
        }
        print("\(chatMessages[indexPath.item].userSent!.userID) ~ \(CurrentAccount.user!.userID)")
        var identifier = "chatBoxNotToday"
        if chatMessages[indexPath.item].userSent!.userID == CurrentAccount.user!.userID {
            identifier = "chatBoxNotTodayMe"
            print("Heuh")
        }

        let cell = tableView.dequeueReusableCellWithIdentifier(identifier, forIndexPath: indexPath) as! ChatMessageNotTodayTableViewCell

        cell.configureCellWithChatMessage(chatMessages[indexPath.row])

        return cell
    } else {
        let cell = tableView.dequeueReusableCellWithIdentifier("channelCell") as! UITableViewCell
        if indexPath.section == 2 {
            //private messages
            cell.textLabel?.text = "\(CurrentAccount.friends[indexPath.row].firstName!) \(CurrentAccount.friends[indexPath.row].lastName!)"
        } else {
            var num = 0
            if indexPath.section == 1 {
                num = Channel.publicChannels
            }
            cell.textLabel?.text = "\(channelList[num + indexPath.item].name)"
        }

        return cell
    }
}

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
    //messageTextField.delegate = self
    setUpTopBarIcons()
    getAllParseChannels()
}

func loadFirstParseChannel() {
    if channelList.count > 0 {
        selectedChannel = channelList[0]
        if selectedChannel!.tag == 3 {
            setUpTopBarForPrivateChatLabels()
        } else {
            setUpTopBarForOtherChatLabels()
        }
        loadMessagesForSelectedChannel()
    }
}

func setUpTopBarIcons() {
    topVideoButton.titleLabel?.font = UIFont.fontAwesomeOfSize(17)
    topVoiceButton.titleLabel?.font = UIFont.fontAwesomeOfSize(17)
    topVideoButton.titleLabel?.text = String.fontAwesomeIconWithName(FontAwesome.VideoCamera)
    topVoiceButton.titleLabel?.text = String.fontAwesomeIconWithName(FontAwesome.VolumeUp)
}

func setUpTopBarForPrivateChatLabels() {
    let user: User!
    if selectedChannel?.users[0].userID == CurrentAccount.user?.userID {
        //set user to other user
        user = selectedChannel?.users[1]
    } else {
        user = selectedChannel?.users[0]
    }
    topNameLabel.text = "\(user.firstName!) \(user.lastName!)"
    topJobLabel.text = "Medical Marijuana Treatment Specialist"
    topOfficeLabel.text = "420 Evaluations - San Jose"
    topBarOtherChat.hidden = true
    topBarPrivateChat.hidden = false
}

func setUpTopBarForOtherChatLabels() {
    topChannelNameLabel.text = "\(selectedChannel!.name)"
    topNumberPeopleLabel.text = "\(selectedChannel!.users.count)"
    topTypeChannelIconLabel.font = UIFont.fontAwesomeOfSize(30)
    topTypeChannelIconLabel.text = String.fontAwesomeIconWithName(FontAwesome.Users)
    if selectedChannel?.tag == 1 {
        //Public Channel
        topTypeChannelLabel.text = "Public Chat"
    } else {
        //Group Channel
        topTypeChannelLabel.text = "Group Chat"
    }
    topBarOtherChat.hidden = false
    topBarPrivateChat.hidden = true
}

func sendParseChatMessageObject(message: ChatMessage) {
    selectedChannel!.sendMessage(message)
}

func getAllParseChannels() {
    let query: PFQuery = PFQuery(className: "TestChannels")
    query.findObjectsInBackgroundWithBlock { (objects: [AnyObject]?, error: NSError?) -> Void in
        if let error = error {
            // There was an error
            print("error getting parse channels")
        } else {
            //all the channels are here
            if let channels: [PFObject] = objects as? [PFObject]
            {
                for channel in channels {
                    self.channelList.append(Channel(obj: channel))
                }
                self.channelsTableView.reloadData()
                self.loadFirstParseChannel()
                self.startTimers()
            }
        }
    }
}

func loadMessagesForSelectedChannel() {
    chatMessages = selectedChannel!.messages
    dispatch_async(dispatch_get_main_queue()) {
        self.tableView.reloadData()
    }

    //self.tableView.reloadData()
    //self.tableView.layoutIfNeeded()
    //print("\n\n\n\(tableView.numberOfRowsInSection(0))\n\n\n")
    //self.tableView.scrollToRowAtIndexPath(NSIndexPath(forRow: (self.chatMessages.count - 1), inSection: 0), atScrollPosition: UITableViewScrollPosition.Bottom, animated: true)
    //print("done")
}

func startTimers() {
    selectedChannelTimer = NSTimer(timeInterval: 3.0, target: self, selector: "checkAndUpdateMessagesInSelectedChannel", userInfo: nil, repeats: true)
    NSRunLoop.currentRunLoop().addTimer(selectedChannelTimer, forMode: NSRunLoopCommonModes)
    //allChannelsTimer = NSTimer(timeInterval: 10.0, target: self, selector: "checkAndUpdateMessagesInAllChannels", userInfo: nil, repeats: true)
    //NSRunLoop.currentRunLoop().addTimer(allChannelsTimer, forMode: NSRunLoopCommonModes)
}

//Check every 1-3 seconds
func checkAndUpdateMessagesInSelectedChannel() {
    print("HERE BITCHES")
    let query: PFQuery = PFQuery(className: "TestMessage")
    query.whereKey("channel_id", equalTo: selectedChannel!.channelID)
    query.findObjectsInBackgroundWithBlock { (objects: [AnyObject]?, error: NSError?) -> Void in
        if let error = error {
            // There was an error
            print("error getting parse messages")
        } else {
            // objects has all the Posts the current user liked.
            if let messages: [PFObject] = objects as? [PFObject]
            {
                self.chatMessages.removeAll(keepCapacity: false)
                for message in messages {
                    self.chatMessages.append(ChatMessage(message: message["message_text"]! as! NSString as! String, dateSent: message.createdAt!, userSent: JSONParser.userFromUserID(JSONParser.getUsers()!, id: message["send_user_id"]! as! NSString as! String)!))
                }
                self.chatMessages.sort({$0.dateSent!.timeIntervalSinceNow < $1.dateSent!.timeIntervalSinceNow})

                self.tableView.reloadData()
            }
        }
    }
}

//Every 10 seconds call this
func checkAndUpdateMessagesInAllChannels() {
    //I need a dictionary that goes "channelID" -> Int(numberInArray)
    var dict = [String:Int]()
    var num = 0
    for channel in channelList {
        dict["\(channel.channelID)"] = num
        num += 1
    }
    //I should move the above code somewhere else, so it doesn't keep being coded
    let query: PFQuery = PFQuery(className: "TestMessage")
    query.findObjectsInBackgroundWithBlock { (objects: [AnyObject]?, error: NSError?) -> Void in
        if let error = error {
            // There was an error
            print("error getting parse messages")
        } else {
            // objects has all the Posts the current user liked.
            if let messages: [PFObject] = objects as? [PFObject]
            {
                //Clear messages for all channels
                for channel in self.channelList {
                    channel.messages.removeAll(keepCapacity: false)
                }
                for message in messages {
                    num = dict[message["channel_id"]! as! NSString as! String]!
                    self.channelList[num].messages.append(ChatMessage(message: message["message_text"]! as! NSString as! String, dateSent: message.createdAt!, userSent: CurrentAccount.user!))
                }
                self.chatMessages.sort({$0.dateSent!.timeIntervalSinceNow < $1.dateSent!.timeIntervalSinceNow})
                self.tableView.reloadData()
            }
        }
    }
    //Later find a way to see if a channel gained a new message
}

func getAllParseMessages() {
    let query: PFQuery = PFQuery(className: "TestMessage")
    query.findObjectsInBackgroundWithBlock { (objects: [AnyObject]?, error: NSError?) -> Void in
        if let error = error {
            // There was an error
            print("error getting parse messages")
        } else {
            // objects has all the Posts the current user liked.
            if let messages: [PFObject] = objects as? [PFObject]
            {
                for message in messages {
                    self.chatMessages.append(ChatMessage(message: message["message_text"]! as! NSString as! String, dateSent: message.createdAt!, userSent: CurrentAccount.user!))
                }
                self.chatMessages.sort({$0.dateSent!.timeIntervalSinceNow < $1.dateSent!.timeIntervalSinceNow})

                self.tableView.reloadData()
            }
        }
    }
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}


}

Update: I think my compiler thinks my second view uses the same view controller as the first, and as such all the IBOutlets are nil. 更新:我认为我的编译器认为我的第二个视图使用与第一个相同的视图控制器,因此所有IBOutlets均为零。 I 一世
think this because the method viewDidLoad is being called when I do 认为这是因为在执行此操作时会调用viewDidLoad方法
the segue. segue。

No, it thinks that your second view controller uses "the same controller as the first" because your second view controller is defined by YOU as a subclass of ViewController . 不,它认为您的第二个视图控制器使用“与第一个相同的控制器”,因为您将第二个视图控制器定义为ViewController的子类。 Therefore, it has all the same IBOutlets defined, but they are not connected. 因此,它定义了所有相同的IBOutlet,但它们未连接。

When viewDidLoad is called function setUpTopBarIcons is triggered. 调用viewDidLoad ,将触发setUpTopBarIcons函数。 topVideoButton gets accessed but because you have not connected it compiler debugger throws an error: 访问了topVideoButton ,但由于尚未连接,因此编译器调试器将引发错误:

Unexpectedly found nil while unwrapping an optional value. 展开一个可选值时意外找到nil。

There are two ways out of this: 有两种解决方法:

  1. Connect all IBOutlets in your NewChannelPickerViewController NewChannelPickerViewController连接所有IBOutlets
    (those which are defined by ViewController ) (那些由ViewController定义)
  2. If you cannot accomplish (1) it means that you should define 如果您无法完成(1),则意味着您应该定义
    NewChannelPickerViewController as a subclass of UIViewController and not as a subclass of ViewController NewChannelPickerViewController作为UIViewController的子类,而不作为ViewController的子类

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM