在开始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.
}
}
答案 0 :(得分:3)
更新:我认为我的编译器认为我的第二个视图使用相同的视图 控制器作为第一个,因此所有IBOutlets都是零。我
认为这是因为当我执行时调用viewDidLoad方法 segue。
不,它认为你的第二个视图控制器使用“与第一个相同的控制器”
因为您的第二个视图控制器是由您定义的子类
ViewController
。因此,它定义了所有相同的IBOutlets,但它们不是
连接的。
当调用viewDidLoad
时,会触发函数setUpTopBarIcons
。
访问topVideoButton
,但因为您没有连接它编译器
调试器抛出错误:
在展开可选值时意外地发现了nil。
有两种方法:
IBOutlets
中的所有NewChannelPickerViewController
(由ViewController
)NewChannelPickerViewController
作为UIViewController
的子类
而不是ViewController