斯威夫特:IBOutlets在现在的模态下是零

时间:2015-08-13 18:06:08

标签: ios swift

在开始segue之前,我的所有商店都不是零,并且工作正常。但是,一旦演示发生,第一个视图控制器的IBOutlets就是零,我的编译器说Unexpectedly found nil while unwrapping an optional value.

我没有使用任何特别的演示文稿或segue,为什么会发生这种情况?我可以告诉你什么代码?

我在第一个视图控制器上有定时器访问第一个视图控制器中的IBOutlets:这可能是问题吗?

更新:我认为我的编译器认为我的第二个视图使用与第一个视图控制器相同的视图控制器,因此所有IBOutlet都是零。我认为这是因为当我执行segue时调用方法viewDidLoad

更新:您可以在此处下载我的源代码:Source Code

更新:这是我的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.
}


}

1 个答案:

答案 0 :(得分:3)

  

更新:我认为我的编译器认为我的第二个视图使用相同的视图   控制器作为第一个,因此所有IBOutlets都是零。我
  认为这是因为当我执行时调用viewDidLoad方法   segue。

不,它认为你的第二个视图控制器使用“与第一个相同的控制器” 因为您的第二个视图控制器是由您定义的子类 ViewController。因此,它定义了所有相同的IBOutlets,但它们不是 连接的。

当调用viewDidLoad时,会触发函数setUpTopBarIcons。 访问topVideoButton,但因为您没有连接它编译器 调试器抛出错误:

  

在展开可选值时意外地发现了nil。

有两种方法:

  1. 连接IBOutlets中的所有NewChannelPickerViewController (由ViewController
  2. 定义的那些
  3. 如果你不能完成(1)则意味着你应该定义
    NewChannelPickerViewController作为UIViewController的子类     而不是ViewController
  4. 的子类