[英]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: 有两种解决方法:
IBOutlets
in your NewChannelPickerViewController
NewChannelPickerViewController
连接所有IBOutlets
ViewController
) ViewController
定义) NewChannelPickerViewController
as a subclass of UIViewController
and not as a subclass of ViewController
NewChannelPickerViewController
作为UIViewController
的子类,而不作为ViewController
的子类
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.