我构建了一个允许用户与AWS Lex聊天机器人通信的应用程序,但现在的问题是当用户点击按钮开始与机器人的对话时崩溃并给我一个线程1:此行上的EXC_BAD_INSTRUCTION 错误:
let configuration = AWSServiceConfiguration(region: botRegion!, credentialsProvider: AWSIdentityManager.default().credentialsProvider)
我真的很想知道是什么导致它表现得像这样,因为Xcode没有强调代码的任何重要部分。
以下是我感兴趣的代码的全部内容。
import Foundation
import UIKit
import Photos
import JSQMessagesViewController
import AWSLex
import AWSMobileHubHelper
let ClientSenderId = "Client"
let ServerSenderId = "Server"
class JeevesChatViewController: JSQMessagesViewController, JSQMessagesComposerTextViewPasteDelegate {
// The name of the bot.
var botName: String?
// The bot region
var botRegion: AWSRegionType?
// The bot alias
var botAlias: String?
// The messages communicated between the client and the server
var messages: [JSQMessage]?
// The interaction kit client
var interactionKit: AWSLexInteractionKit?
// The session attributes
var sessionAttributes: [AnyHashable: Any]?
// Contents of outgoing image
var outgoingBubbleImageData: JSQMessagesBubbleImage?
// Contents of incoming image
var incomingBubbleImageData: JSQMessagesBubbleImage?
// Used to store task completion source of iteraction kit
var textModeSwitchingCompletion: AWSTaskCompletionSource<NSString>?
// The client image
var clientImage: JSQMessagesAvatarImage?
// The bot image
var serverImage: JSQMessagesAvatarImage?
override func viewDidLoad() {
super.viewDidLoad()
// Make the initial setup for the bot.
// Error occurs here - fatal error: unexpectedly found nil while unwrapping an Optional value
let configuration = AWSServiceConfiguration(region: botRegion!, credentialsProvider: AWSIdentityManager.default().credentialsProvider)
// Setup interaction kit configuration
let botConfig = AWSLexInteractionKitConfig.defaultInteractionKitConfig(withBotName:botName!, botAlias: botAlias!)
// Disable automatic voice playback
botConfig.autoPlayback = false
// Register the interaction kit client
AWSLexInteractionKit.register(with: configuration!, interactionKitConfiguration: botConfig, forKey: botName!)
// Fetch and set the interaction kit client
self.interactionKit = AWSLexInteractionKit.init(forKey: botName!)
// Set the interaction kit delegate
// Remove 'as? AWSLexInteractionDelegate' statement later
self.interactionKit?.interactionDelegate = self
// Setup JSQMessagesViewController configuration
self.showLoadEarlierMessagesHeader = false
// Initialise the avatars for client and server here.
// Setup the default keyboard type.
self.inputToolbar.contentView?.textView?.keyboardType = UIKeyboardType.default
// Initialise the messages list
self.messages = [JSQMessage]()
// Set the colours for messages bubbles
let bubbleFactory = JSQMessagesBubbleImageFactory()
self.outgoingBubbleImageData = bubbleFactory?.outgoingMessagesBubbleImage(with: UIColor.jsq_messageBubbleGreen())
self.incomingBubbleImageData = bubbleFactory?.incomingMessagesBubbleImage(with: UIColor.jsq_messageBubbleBlue())
self.inputToolbar.contentView?.leftBarButtonItem = nil
self.senderDisplayName = "User"
self.senderId = ClientSenderId
}
// MARK: - JSQMessagesViewController delegate methods
override func didPressSend(_ button: UIButton!, withMessageText text: String!, senderId: String!, senderDisplayName: String!, date: Date!) {
let message = JSQMessage(senderId: senderId, senderDisplayName: senderDisplayName, date: date, text: text)
self.messages?.append(message!)
if let textModeSwitchingCompletion = textModeSwitchingCompletion {
textModeSwitchingCompletion.set(result: text as NSString)
self.textModeSwitchingCompletion = nil
}
else {
self.interactionKit?.text(inTextOut: text)
}
self.finishSendingMessage(animated: true)
}
override func collectionView(_ collectionView: JSQMessagesCollectionView, messageDataForItemAt indexPath: IndexPath) -> JSQMessageData {
return self.messages![indexPath.item]
}
override func collectionView(_ collectionView: JSQMessagesCollectionView, didDeleteMessageAt indexPath: IndexPath) {
// Nothing happens here
}
override func collectionView(_ collectionView: JSQMessagesCollectionView, messageBubbleImageDataForItemAt indexPath: IndexPath) -> JSQMessageBubbleImageDataSource {
let message = self.messages![indexPath.item]
if (message.senderId == self.senderId) {
return self.outgoingBubbleImageData!
}
return self.incomingBubbleImageData!
}
override func collectionView(_ collectionView: JSQMessagesCollectionView, avatarImageDataForItemAt indexPath: IndexPath) -> JSQMessageAvatarImageDataSource? {
let message = messages![indexPath.item]
if message.senderId == ClientSenderId {
return self.clientImage
}
return self.serverImage
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if let messages = messages {
return messages.count
}
return 0
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = (super.collectionView(collectionView, cellForItemAt: indexPath) as! JSQMessagesCollectionViewCell)
let msg = self.messages?[indexPath.item]
if !msg!.isMediaMessage {
if (msg?.senderId == self.senderId) {
cell.textView?.textColor = UIColor.black
}
else {
cell.textView?.textColor = UIColor.white
}
}
return cell
}
override func collectionView(_ collectionView: JSQMessagesCollectionView, attributedTextForCellTopLabelAt indexPath: IndexPath) -> NSAttributedString? {
if indexPath.item % 3 == 0 {
let message = self.messages?[indexPath.item]
return JSQMessagesTimestampFormatter.shared().attributedTimestamp(for: message!.date)
}
return nil
}
override func collectionView(_ collectionView: JSQMessagesCollectionView, attributedTextForMessageBubbleTopLabelAt indexPath: IndexPath) -> NSAttributedString? {
let message = self.messages?[indexPath.item]
// iOS 7 sender name labels
if (message?.senderId == self.senderId) {
return nil
}
if indexPath.item - 1 > 0 {
let previousMessage = self.messages?[indexPath.item - 1]
if (previousMessage?.senderId == message?.senderId) {
return nil
}
}
// Do not specify attributes to use the default values.
return NSAttributedString(string: message!.senderDisplayName)
}
override func collectionView(_ collectionView: JSQMessagesCollectionView, attributedTextForCellBottomLabelAt indexPath: IndexPath) -> NSAttributedString? {
return nil
}
func composerTextView(_ textView: JSQMessagesComposerTextView, shouldPasteWithSender sender: Any) -> Bool {
return true
}
}
// MARK: - Bot Interaction Kit
extension JeevesChatViewController: AWSLexInteractionDelegate {
func interactionKit(_ interactionKit: AWSLexInteractionKit, onError error: Error) {
print("Error occurred: \(error)")
}
func interactionKit(_ interactionKit: AWSLexInteractionKit, switchModeInput: AWSLexSwitchModeInput, completionSource: AWSTaskCompletionSource<AWSLexSwitchModeResponse>?) {
self.sessionAttributes = switchModeInput.sessionAttributes
DispatchQueue.main.async(execute: {
let message: JSQMessage
// Handle a successful transaction
if (switchModeInput.dialogState == AWSLexDialogState.readyForFulfillment) {
// Currently just displaying the slots return on ready for fulfillment
if let slots = switchModeInput.slots {
message = JSQMessage(senderId: ServerSenderId, senderDisplayName: "", date: Date(), text: "Slots:\n\(slots)")
self.messages?.append(message)
self.finishSendingMessage(animated: true)
}
} else {
message = JSQMessage(senderId: ServerSenderId, senderDisplayName: "", date: Date(), text: switchModeInput.outputText!)
self.messages?.append(message)
self.finishSendingMessage(animated: true)
}
})
// This can be expanded to take input from the user.
let switchModeResponse = AWSLexSwitchModeResponse()
switchModeResponse.interactionMode = AWSLexInteractionMode.text
switchModeResponse.sessionAttributes = switchModeInput.sessionAttributes
completionSource?.set(result: switchModeResponse)
}
func interactionKitContinue(withText interactionKit: AWSLexInteractionKit, completionSource: AWSTaskCompletionSource<NSString>) {
textModeSwitchingCompletion = completionSource
}
}
答案 0 :(得分:0)
您尚未正确设置您的credentialsProvider。 AWSIdentityManager从未被初始化为:
let configuration = AWSServiceConfiguration(region: botRegion!, credentialsProvider: AWSIdentityManager.default().credentialsProvider)
如果您使用AWS for S3存储桶,则应使用隐身模式,因此
let cognitoIdentityPoolId = //"XYZ"
let cognitoUnauthRoleArn = //"XYZ"
let cognitoAuthRoleArn = //"XYZ"
let credentialsProvider = AWSCognitoCredentialsProvider(regionType: #Wherever, identityPoolId: cognitoIdentityPoolId, unauthRoleArn: cognitoUnauthRoleArn, authRoleArn: cognitoAuthRoleArn, identityProviderManager: nil)
然后您可以将您的行更改为:
let configuration = AWSServiceConfiguration(region: botRegion!, credentialsProvider: credentialsProvider)