Swift crash when player gets notification for their turn - swift

Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value: file HATurnBasedMatchHelper.swift, line 244
2021-01-25 20:36:22.317564-0500 QuizApp[14288:4507393] Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value: file HATurnBasedMatchHelper.swift, line 244
func player(_ player: GKPlayer, receivedTurnEventFor match: GKTurnBasedMatch, didBecomeActive: Bool) {
// Crash on Line 244
// state of self when using notification
/*
self QuizApp.HATurnBasedMatchHelper 0x0000000281a4c310
ObjectiveC.NSObject NSObject
reachability QuizApp.Reachability? 0x0000000281a4c7e0
saveToLoseList Bool? false some
isMultiplayerGame Bool? false some
currentMatch GKTurnBasedMatch? 0x0000000283e29530
selectedCategory QuizApp.HACategory? nil none
delegate QuizApp.HATurnbasedMatchHelperDelegate? nil none
presentingViewController UIViewController? nil none
myWins Int64 1
pendingWins Int64 0
takeAnotherChallenge Bool? false some
*/
/* I added the if condition to check if the VC is nil */
if self.presentingViewController != nil {
self.presentingViewController.dismiss(animated: true, completion: nil)
}
self.currentMatch = match
let firstParticipant = match.participants[0]
if firstParticipant.lastTurnDate == nil
{
delegate.enterNewGame(match: match)
}
else{
var statusString : String? = nil
var thisParticipant : GKTurnBasedParticipant? = nil
var otherParticipant : GKTurnBasedParticipant? = nil
for participant in match.participants
{
if participant.player?.playerID == GKLocalPlayer.local.playerID
{
thisParticipant = participant
}
else{
otherParticipant = participant
}
}
if thisParticipant?.matchOutcome == .quit {
statusString = "You have Quit this match"
}
else if otherParticipant?.matchOutcome == .quit
{
statusString = "Opponent has Quit this match"
}
else if otherParticipant?.status == .declined
{
statusString = "Opponent has Declined your challenge"
}
if statusString == nil{
if match.currentParticipant?.player?.playerID == GKLocalPlayer.local.playerID
{
// crash here
// delegat is nil. I posted all values of self above
delegate.takeTurn(match: match)
}
else{
delegate.layout(match: match)
}
}
else{
let alertController = UIAlertController(title: "Match status\n", message:statusString , preferredStyle: .alert)
let okAction = UIAlertAction(title: "Ok", style: .default) { (action) in
}
alertController.addAction(okAction)
self.presentingViewController.present(alertController, animated: true, completion: nil)
}
}
}
I am not sure what I am doing wrong here.
The exact error is
Thread 1: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value

Related

Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value - Cant figure out why it's nil [duplicate]

This question already has answers here:
What does "Fatal error: Unexpectedly found nil while unwrapping an Optional value" mean?
(16 answers)
Closed 3 years ago.
I am getting this error and I for the life of me cannot figure out why it is returning a nil value.
Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value
The error is occurring at:
} else {
gameInfo.player = players
self.performSegue(withIdentifier: "ServerView", sender: self)
}
Here is my full set of code below starting with the table view controller.
class PlayerSelectViewController: UIViewController {
#IBOutlet weak var playerButton: UIButton!
#IBOutlet weak var playersTextBox: UITextField!
var gameInfo:GameInfo!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func cancelBtnClicked(_ sender: Any) {
self.navigationController?.popToRootViewController(animated: true)
}
#IBAction func okBtnClicked(_ sender: Any) {
guard let players = Int(playersTextBox.text!) else {
makeAlert(title: "Enter a Number", message: "Please enter a number and then press Ok")
return
}
if players < 2 {
makeAlert(title: "Incorrect Number", message: "Please input more than \(playersTextBox.text!)")
} else if players > 50 {
makeAlert(title: "Incorrect Number", message: "Please input less than \(playersTextBox.text!)")
} else {
gameInfo.player = players
self.performSegue(withIdentifier: "ServerView", sender: self)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let playerController = segue.destination as! ServerSelectViewController
playerController.gameInfo = gameInfo
}
func makeAlert (title: String, message: String) {
let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertController.Style.alert)
alert.addAction(UIAlertAction(title: "Ok", style: UIAlertAction.Style.default, handler: {(action) in
alert.dismiss(animated: true, completion: nil)}))
self.present(alert, animated: true, completion: nil)
}
This is my Model.
class GameInfo: Codable {
var player: Int
var numberPicked: Int
var datePlayed: Date
var winner: String
var turn: Int
init(player: Int, numberPicked: Int, datePlayed: Date, winner: String, turn: Int) {
self.player = player
self.numberPicked = numberPicked
self.datePlayed = datePlayed
self.winner = winner
self.turn = turn
}
static func loadGameInfo() -> [GameInfo] {
return []
}
static let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
static let archiveURL = documentsDirectory.appendingPathComponent("gameInformation").appendingPathExtension("plist")
static func saveToFile(gameInformation: [GameInfo]) {
let propertyListEncoder = PropertyListEncoder()
let gameInfo = try? propertyListEncoder.encode(gameInformation)
try? gameInfo?.write(to: archiveURL, options: .noFileProtection)
}
static func loadFromFile() -> [GameInfo]? {
guard let gameInfo = try? Data(contentsOf: archiveURL) else { return nil }
let propertyListDecoder = PropertyListDecoder()
return try? propertyListDecoder.decode(Array<GameInfo>.self, from: gameInfo)
}
}
Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value
so check the implicitly unwrapped optionals in your code.
Your options seem to be:
#IBOutlet weak var playerButton: UIButton!
#IBOutlet weak var playersTextBox: UITextField!
var gameInfo:GameInfo!
Which one is never assigned a value?

How to limit character for username in Swift

i need to limit character for username in my swift code.
Username only can use those characters "abcdefghijklmnopqrstuvwxyz._1234567890".
Please forgive me if i'm noob, i don't have programming background. Still learning .
Below are swift code, which part i need to edit ?
// MARK: - SIGNUP BUTTON
#IBAction func signupButt(_ sender: AnyObject) {
dismissKeyboard()
// You acepted the TOS
if tosAccepted {
if usernameTxt.text == "" || passwordTxt.text == "" || emailTxt.text == "" || fullnameTxt.text == "" {
simpleAlert("You must fill all fields to sign up on \(APP_NAME)")
self.hideHUD()
} else {
showHUD("Please wait...")
let userForSignUp = PFUser()
userForSignUp.username = usernameTxt.text!.lowercased()
userForSignUp.password = passwordTxt.text
userForSignUp.email = emailTxt.text
userForSignUp[USER_FULLNAME] = fullnameTxt.text
userForSignUp[USER_IS_REPORTED] = false
let hasBlocked = [String]()
userForSignUp[USER_HAS_BLOCKED] = hasBlocked
// Save Avatar
let imageData = avatarImg.image!.jpegData(compressionQuality: 1.0)
let imageFile = PFFile(name:"avatar.jpg", data:imageData!)
userForSignUp[USER_AVATAR] = imageFile
userForSignUp.signUpInBackground { (succeeded, error) -> Void in
if error == nil {
self.hideHUD()
let alert = UIAlertController(title: APP_NAME,
message: "We have sent you an email that contains a link - you must click this link to verify your email and go back here to login.",
preferredStyle: .alert)
// Logout and Go back to Login screen
let ok = UIAlertAction(title: "OK", style: .default, handler: { (action) -> Void in
PFUser.logOutInBackground(block: { (error) in
self.dismiss(animated: false, completion: nil)
})
})
alert.addAction(ok)
self.present(alert, animated: true, completion: nil)
// ERROR
} else {
self.simpleAlert("\(error!.localizedDescription)")
self.hideHUD()
}}
}
You can use regex for this, check out the code below.
let usernameRegex = "^[a-zA-Z0-9]{4,10}$"
let usernameTest = NSPredicate(format:"SELF MATCHES %#", usernameRegex)
print(usernameTest.evaluate(with: "asAZ")) // boolen
You can even create an extension out of it like this
extension String {
func isValidUserName() -> Bool{
let usernameRegex = "^[a-zA-Z0-9]{4,10}$" // your regex
let usernameTest = NSPredicate(format:"SELF MATCHES %#", usernameRegex)
return usernameTest.evaluate(with: self)
}
}
use it like this
yourText.isValidUserName() // return true or false .
You can google any kind of regex to fit your case, and future ones, i even recommend saving those regex in an enum, and create a function that accept those enums and validate, look at this as a hint
enum ValidationRgex: String {
case username = "^[a-zA-Z0-9]{4,10}$"
}
extension String {
func isValid(_ regex: ValidationRgex) -> Bool{
let usernameRegex = regex.rawValue
let usernameTest = NSPredicate(format:"SELF MATCHES %#", usernameRegex)
return usernameTest.evaluate(with: self)
}
}
"MyText".isValid(.username) // usage

Firestore database does not store data

I've created an app in which, when the user signs up, should create two values in the Firestore server in the user's document, that is level and subjects (meaning it's in /users/userid).
I've tried manually creating the 'users' collection, but nothing is being created when the user signs up.
The following is my code (SignUpViewController):
import Firebase
var reference: DocumentReference!
func firebaseAuth() {
let userDisplayName = textfieldDisplayName.text!
let userEmail = textfieldEmail.text!
let userPassword = textfieldPassword.text!
if userEmail == "" || userPassword == "" {
labelMessage.isHidden = false
labelMessage.textColor = UIColor.red
labelMessage.text = "Error: A compulsory field is left blank."
} else {
Auth.auth().createUser(withEmail: userEmail, password: userPassword) { (user, error) in
if user != nil && error == nil {
let changeRequest = Auth.auth().currentUser?.createProfileChangeRequest()
changeRequest?.displayName = userDisplayName
changeRequest?.commitChanges(completion: { (error) in
if error == nil {
let userID = Auth.auth().currentUser?.uid
let dataToSave: [String: Any] = ["level":0, "subjects":[""]]
self.reference = Firestore.firestore().collection("users").document(userID ?? "")
self.reference.setData(dataToSave, completion: { (error) in
if error == nil {
self.performSegue(withIdentifier: "presentInitial", sender: self)
} else {
self.labelMessage.isHidden = false
self.labelMessage.textColor = UIColor.red
self.labelMessage.text = "Error: \(error?.localizedDescription ?? "")"
}
})
self.performSegue(withIdentifier: "presentInitial", sender: self)
} else {
self.labelMessage.isHidden = false
self.labelMessage.textColor = UIColor.red
self.labelMessage.text = "Error: \(error?.localizedDescription ?? "")"
}
})
} else {
self.labelMessage.isHidden = false
self.labelMessage.textColor = UIColor.red
self.labelMessage.text = "Error: \(error?.localizedDescription ?? "")"
}
}
}
}
The following code is from another View Controller which SignUpViewController redirects to (HomeViewController):
import Firebase
var reference: DocumentReference!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let userID = Auth.auth().currentUser?.uid
reference.getDocument { (docSnapshot, error) in // Fatal error occured here
let data = docSnapshot?.data()
let userLevel = data?["level"] as? String ?? ""
if userLevel == "" {
self.performSegue(withIdentifier: "performSetup", sender: self)
}
}
}
I expected that when redirected to the homepage (segued through presentInitial), the homepage will then read the value of 'level'. However, the app crashed with a fatal error: "Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value" where 'level' was meant to be read from the server.
I think the problem is not with Firestore. According to the error message, the code wraps an optional value but failed because it is nil, so the problem is probably about these three lines:
let userDisplayName = textfieldDisplayName.text!
let userEmail = textfieldEmail.text!
let userPassword = textfieldPassword.text!
Sometimes, when a UITextField has no text, its text is nil instead of "", which may cause the problem. You can replace the three lines with the following:
let userDisplayName = textfieldDisplayName.text ?? ""
let userEmail = textfieldEmail.text ?? ""
let userPassword = textfieldPassword.text ?? ""
In this way, these three variables will always be "" when there are no text, and your logic of checking blank fields will still work.
Edit: For future reference, the real problem is not in the question but in the comments of this answer.
Did you check your database rules ?
you need to setup the rules when to work and when not to so no one can access the database but your apps
for a test now use this code to verify it woks then you should change it
{
"rules": {
".read": true,
".write": true
}
}

List all available audio devices

I want to list all available audio devices in swift to provide a selection for input and output. My application should listen on a audio channel and "write" to another. I do not want the system default!
let devices = AVCaptureDevice.devices(for: .audio)
print(devices.count)
for device in devices {
print(device.localizedName)
}
The Code lists 0 devices. But I expect at least the internal output.
Some links to CoreAudio, AudioToolbox and AVFoundation that explain the audio source selection would be nice.
Here's some Swift 5 code that will enumerate all the audio devices.
You can use the uid with AVAudioPlayer's currentDevice property to output to a specific device.
import Cocoa
import AVFoundation
class AudioDevice {
var audioDeviceID:AudioDeviceID
init(deviceID:AudioDeviceID) {
self.audioDeviceID = deviceID
}
var hasOutput: Bool {
get {
var address:AudioObjectPropertyAddress = AudioObjectPropertyAddress(
mSelector:AudioObjectPropertySelector(kAudioDevicePropertyStreamConfiguration),
mScope:AudioObjectPropertyScope(kAudioDevicePropertyScopeOutput),
mElement:0)
var propsize:UInt32 = UInt32(MemoryLayout<CFString?>.size);
var result:OSStatus = AudioObjectGetPropertyDataSize(self.audioDeviceID, &address, 0, nil, &propsize);
if (result != 0) {
return false;
}
let bufferList = UnsafeMutablePointer<AudioBufferList>.allocate(capacity:Int(propsize))
result = AudioObjectGetPropertyData(self.audioDeviceID, &address, 0, nil, &propsize, bufferList);
if (result != 0) {
return false
}
let buffers = UnsafeMutableAudioBufferListPointer(bufferList)
for bufferNum in 0..<buffers.count {
if buffers[bufferNum].mNumberChannels > 0 {
return true
}
}
return false
}
}
var uid:String? {
get {
var address:AudioObjectPropertyAddress = AudioObjectPropertyAddress(
mSelector:AudioObjectPropertySelector(kAudioDevicePropertyDeviceUID),
mScope:AudioObjectPropertyScope(kAudioObjectPropertyScopeGlobal),
mElement:AudioObjectPropertyElement(kAudioObjectPropertyElementMaster))
var name:CFString? = nil
var propsize:UInt32 = UInt32(MemoryLayout<CFString?>.size)
let result:OSStatus = AudioObjectGetPropertyData(self.audioDeviceID, &address, 0, nil, &propsize, &name)
if (result != 0) {
return nil
}
return name as String?
}
}
var name:String? {
get {
var address:AudioObjectPropertyAddress = AudioObjectPropertyAddress(
mSelector:AudioObjectPropertySelector(kAudioDevicePropertyDeviceNameCFString),
mScope:AudioObjectPropertyScope(kAudioObjectPropertyScopeGlobal),
mElement:AudioObjectPropertyElement(kAudioObjectPropertyElementMaster))
var name:CFString? = nil
var propsize:UInt32 = UInt32(MemoryLayout<CFString?>.size)
let result:OSStatus = AudioObjectGetPropertyData(self.audioDeviceID, &address, 0, nil, &propsize, &name)
if (result != 0) {
return nil
}
return name as String?
}
}
}
class AudioDeviceFinder {
static func findDevices() {
var propsize:UInt32 = 0
var address:AudioObjectPropertyAddress = AudioObjectPropertyAddress(
mSelector:AudioObjectPropertySelector(kAudioHardwarePropertyDevices),
mScope:AudioObjectPropertyScope(kAudioObjectPropertyScopeGlobal),
mElement:AudioObjectPropertyElement(kAudioObjectPropertyElementMaster))
var result:OSStatus = AudioObjectGetPropertyDataSize(AudioObjectID(kAudioObjectSystemObject), &address, UInt32(MemoryLayout<AudioObjectPropertyAddress>.size), nil, &propsize)
if (result != 0) {
print("Error \(result) from AudioObjectGetPropertyDataSize")
return
}
let numDevices = Int(propsize / UInt32(MemoryLayout<AudioDeviceID>.size))
var devids = [AudioDeviceID]()
for _ in 0..<numDevices {
devids.append(AudioDeviceID())
}
result = AudioObjectGetPropertyData(AudioObjectID(kAudioObjectSystemObject), &address, 0, nil, &propsize, &devids);
if (result != 0) {
print("Error \(result) from AudioObjectGetPropertyData")
return
}
for i in 0..<numDevices {
let audioDevice = AudioDevice(deviceID:devids[i])
if (audioDevice.hasOutput) {
if let name = audioDevice.name,
let uid = audioDevice.uid {
print("Found device \"\(name)\", uid=\(uid)")
}
}
}
}
}
The code you posted works perfectly fine for audio input devices when I paste it into an Xcode Playground.
Note, however, that AVCaptureDevice API does not list audio output devices as they are no capture devices but playback devices. If a device supports both, input and output, you can still use the device's uniqueID in an output context, for example with AVPlayer's audioOutputDeviceUniqueID.
(Also note, that if you want your code to work on iOS as well, devices(for:) is marked as deprecated since iOS 11 and you should move to AVCaptureDevice.DiscoverySession instead.)
Regarding your request for additional info on Core Audio and AudioToolbox, this SO question has some pretty comprehensive answers on the matter. The question asks for input devices but the answers provide enough context to let you understand handling of the output side as well. There's even an answer with some (dated) Swift code. On a personal note I have to say calling Core Audio API from Swift is oftentimes more pain than gain. Because of that it might be faster, although a bit unsafer, wrapping those portions of code into Objective-C or plain C and exposing them via the Swift bridging header, if your project allows it.
If you want something like a actionSheet and need to switch between audio devices seamlessly. Use this code.
Code
import Foundation
import AVFoundation
import UIKit
#objc class AudioDeviceHandler: NSObject {
#objc static let shared = AudioDeviceHandler()
/// Present audio device selection alert
/// - Parameters:
/// - presenterViewController: viewController where the alert need to present
/// - sourceView: alertController source view in case of iPad
#objc func presentAudioOutput(_ presenterViewController : UIViewController, _ sourceView: UIView) {
let speakerTitle = "Speaker"
let headphoneTitle = "Headphones"
let deviceTitle = (UIDevice.current.userInterfaceIdiom == .pad) ? "iPad" : "iPhone"
let cancelTitle = "Cancel"
var deviceAction = UIAlertAction()
var headphonesExist = false
let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
guard let availableInputs = AVAudioSession.sharedInstance().availableInputs else {
print("No inputs available ")
return
}
for audioPort in availableInputs {
switch audioPort.portType {
case .bluetoothA2DP, .bluetoothHFP, .bluetoothLE :
let bluetoothAction = UIAlertAction(title: audioPort.portName, style: .default) { _ in
self.setPreferredInput(port: audioPort)
}
if isCurrentOutput(portType: audioPort.portType) {
bluetoothAction.setValue(true, forKey: "checked")
}
optionMenu.addAction(bluetoothAction)
case .builtInMic, .builtInReceiver:
deviceAction = UIAlertAction(title: deviceTitle, style: .default, handler: { _ in
self.setToDevice(port: audioPort)
})
case .headphones, .headsetMic:
headphonesExist = true
let headphoneAction = UIAlertAction(title: headphoneTitle, style: .default) { _ in
self.setPreferredInput(port: audioPort)
}
if isCurrentOutput(portType: .headphones) || isCurrentOutput(portType: .headsetMic) {
headphoneAction.setValue(true, forKey: "checked")
}
optionMenu.addAction(headphoneAction)
case .carAudio:
let carAction = UIAlertAction(title: audioPort.portName, style: .default) { _ in
self.setPreferredInput(port: audioPort)
}
if isCurrentOutput(portType: audioPort.portType) {
carAction.setValue(true, forKey: "checked")
}
optionMenu.addAction(carAction)
default:
break
}
}
// device actions only required if no headphone available
if !headphonesExist {
if (isCurrentOutput(portType: .builtInReceiver) ||
isCurrentOutput(portType: .builtInMic)) {
deviceAction.setValue(true, forKey: "checked")
}
optionMenu.addAction(deviceAction)
}
// configure speaker action
let speakerAction = UIAlertAction(title: speakerTitle, style: .default) { _ in
self.setOutputToSpeaker()
}
if isCurrentOutput(portType: .builtInSpeaker) {
speakerAction.setValue(true, forKey: "checked")
}
optionMenu.addAction(speakerAction)
// configure cancel action
let cancelAction = UIAlertAction(title: cancelTitle, style: .cancel)
optionMenu.addAction(cancelAction)
optionMenu.modalPresentationStyle = .popover
if let presenter = optionMenu.popoverPresentationController {
presenter.sourceView = sourceView
presenter.sourceRect = sourceView.bounds
}
presenterViewController.present(optionMenu, animated: true, completion: nil)
// auto dismiss after 5 seconds
DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) {
optionMenu.dismiss(animated: true, completion: nil)
}
}
#objc func setOutputToSpeaker() {
do {
try AVAudioSession.sharedInstance().overrideOutputAudioPort(AVAudioSession.PortOverride.speaker)
} catch let error as NSError {
print("audioSession error turning on speaker: \(error.localizedDescription)")
}
}
fileprivate func setPreferredInput(port: AVAudioSessionPortDescription) {
do {
try AVAudioSession.sharedInstance().setPreferredInput(port)
} catch let error as NSError {
print("audioSession error change to input: \(port.portName) with error: \(error.localizedDescription)")
}
}
fileprivate func setToDevice(port: AVAudioSessionPortDescription) {
do {
// remove speaker if needed
try AVAudioSession.sharedInstance().overrideOutputAudioPort(AVAudioSession.PortOverride.none)
// set new input
try AVAudioSession.sharedInstance().setPreferredInput(port)
} catch let error as NSError {
print("audioSession error change to input: \(AVAudioSession.PortOverride.none.rawValue) with error: \(error.localizedDescription)")
}
}
#objc func isCurrentOutput(portType: AVAudioSession.Port) -> Bool {
AVAudioSession.sharedInstance().currentRoute.outputs.contains(where: { $0.portType == portType })
}
}
How to use
class ViewController: UIViewController {
#IBOutlet weak var audioButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func selectAudio(_ sender: Any) {
// present audio device selection action sheet
AudioDeviceHandler.shared.presentAudioOutput(self, audioButton)
}
}
Result
It is possible to list input and output devices. This is a simplification of stevex's answer.
For output devices:
if (audioDevice.hasOutput) {
if let name = audioDevice.name,
let uid = audioDevice.uid {
print("Found device \"\(name)\", uid=\(uid)")
}
}
For input devices:
if (!audioDevice.hasOutput) {
if let name = audioDevice.name,
let uid = audioDevice.uid {
print("Found device \"\(name)\", uid=\(uid)")
}
}
(Notice the ! before audioDevice.hasOutput.)

How can I solve this? How can I fix the fatal error?

This is the code:
override func viewDidLoad() {
super.viewDidLoad()
refresher = UIRefreshControl()
refresher.attributedTitle = NSAttributedString(string: "Pull to refresh")
refresher.addTarget(self, action: "refresh", forControlEvents: UIControlEvents.ValueChanged)
self.tableView.addSubview(refresher)
refresh()
var query = PFUser.query()
query?.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
if let users = objects {
self.usernames.removeAll(keepCapacity: true)
self.userids.removeAll(keepCapacity: true)
self.isFollowing.removeAll(keepCapacity: true)
for object in users {
if let user = object as? PFUser {
if user.objectId! != PFUser.currentUser()?.objectId {
self.usernames.append(user.username!)
self.userids.append(user.objectId!)
var query = PFQuery(className: "followers")
if (PFUser.currentUser() == nil) {
print("currentUser() is nil");
} else if (PFUser.currentUser()!.objectId == nil) {
print("PFUser.currentUser()!.objectId is nil");
} else if (user.objectId == nil) {
print("user.objectId is nil");
}
query.whereKey("follower",equalTo: PFUser.currentUser()!.objectId!)
query.whereKey("following", equalTo: user.objectId!)
query.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
if let objects = objects {
if objects.count > 0 {
self.isFollowing[user.objectId!] = true
} else {
self.isFollowing[user.objectId!] = false
}
}
if self.isFollowing.count == self.usernames.count {
self.tableView.reloadData()
}
})
}
}
}
}
})
}
Whenever I try to run this piece of code, I get an error on the line which says "query.whereKey" that prints to the logs like this:
nilPFUser.currentUser()!.objectId is nilfatal error: unexpectedly
found nil while unwrapping an Optional value
Why is that? How can I fix it? I need help on this one. Be specific.
Thank you.
Again, it unexpectedly found a nil while unwrapping an optional value.