我已将我的应用升级到Swift 3和Xcode 8.1。在此更新之后有一个令人困惑的错误,注意:FriendsViewController.swift
上的Command failed due to signal: Segmentation fault: 11
,但没有其他错误指示。Xcode 8.1命令由于信号失败:分段错误:11
这怎么解决?
更新:新增FriendsViewController代码
import UIKit
import Contacts
import ContactsUI
import Firebase
import FBSDKCoreKit
// Allowing clean removal of objects
extension RangeReplaceableCollection where Iterator.Element : Equatable {
// Remove first collection element that is equal to the given `object`:
mutating func removeObject(_ object : Iterator.Element) {
if let index = self.index(of: object) {
self.remove(at: index)
}
}
}
// For searching
extension FriendsViewController: UISearchResultsUpdating {
// must implement to conform to the UISearchResultsUpdating protocol.
// As well as the scope narrowing
func updateSearchResults(for searchController: UISearchController) {
let searchBar = searchController.searchBar
let scope = searchBar.scopeButtonTitles![searchBar.selectedScopeButtonIndex]
filterContentForSearchText(searchController.searchBar.text!, scope: scope)
}
}
extension FriendsViewController: UISearchBarDelegate {
// This delegate methods gets called when the user switches the scope in the scope bar.
// When that happens, you want to redo the filtering,
func searchBar(_ searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) {
filterContentForSearchText(searchBar.text!, scope: searchBar.scopeButtonTitles![selectedScope])
}
}
class FriendsViewController: UITableViewController, CNContactPickerDelegate {
// MARK: Properties
var firebaseMainURL: String!
@IBOutlet weak var menuButton: UIBarButtonItem!
var contacts = [CNContact]()
var friends: [Friend] = []
var mappedFriends: [Friend] = []
var filterMappedFriends: [Friend] = []
var feastGlobalRef = FeastGlobal.sharedInstance
let rootRef = FIRDatabase.database().reference()
// Ensuring Serial queue
let queue = DispatchQueue(label: "DISPATCH_QUEUE_SERIAL", attributes: [])
// Adding search
let searchController = UISearchController(searchResultsController: nil)
override func viewDidLoad() {
super.viewDidLoad()
if revealViewController() != nil {
menuButton.target = revealViewController()
menuButton.action = #selector(SWRevealViewController.revealToggle(_:))
view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
}
// Creating the search bar, decides when to show and hide results
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false
definesPresentationContext = true
tableView.tableHeaderView = searchController.searchBar
// Adding the scope bar and buttons:
searchController.searchBar.scopeButtonTitles = ["All", "Friend", "A User", "Not User"]
searchController.searchBar.delegate = self
// Main mapping action
self.mapContactsToPresentFriends(feastGlobalRef.userID)
}
override func viewWillAppear(_ animated: Bool) {
//self.clearsSelectionOnViewWillAppear = self.splitViewController!.collapsed
super.viewWillAppear(animated)
}
func findContacts() -> [CNContact] {
let store = CNContactStore()
let keysToFetch = [CNContactFormatter.descriptorForRequiredKeys(for: .fullName),
CNContactImageDataKey,
CNContactPhoneNumbersKey] as [Any]
let fetchRequest = CNContactFetchRequest(keysToFetch: keysToFetch as! [CNKeyDescriptor])
var contacts = [CNContact]()
do {
try store.enumerateContacts(with: fetchRequest, usingBlock: { (contact, stop) -> Void in
contacts.append(contact)
})
}
catch let error as NSError {
print(error.localizedDescription)
}
return contacts
}
// MARK: - Table View
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if searchController.isActive && searchController.searchBar.text != "" {
return filterMappedFriends.count
}
return self.mappedFriends.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let friend: Friend
//let contact = contacts[indexPath.row] as CNContact
let contact = mappedFriends[indexPath.row] as Friend
// Getting phone number (default to first phone number present):
let phoneNumber = contact.phoneNumber
// If searching, then replace
if searchController.isActive && searchController.searchBar.text != "" {
friend = filterMappedFriends[indexPath.row]
} else {
friend = mappedFriends[indexPath.row]
}
// Conditional given relationship:
var status: String!
status = {
switch friend.statusSort {
case 0:
return "Invite to Feast"
case 1:
return "Friend them"
default:
return "" // they are a friend
}
}()
// Update the rows with the proper object
cell.textLabel!.text = "\(friend.name) \(friend.userName)"
cell.detailTextLabel?.text = "\(status)"
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// Ensure controller knows which dataset to pull from,
// so detail view is correct
var friendChat: Friend!
if searchController.isActive && searchController.searchBar.text != "" {
friendChat = filterMappedFriends[indexPath.row]
} else {
friendChat = mappedFriends[indexPath.row]
}
// Now set the conditional cases: if a friend then chat, if user then friend request if not user then can invite them:
if(friendChat.statusSort == 2) {
self.performSegue(withIdentifier: "showIndividualChat", sender: self)
} else if (friendChat.statusSort == 1) {
let formatterShortDate = Date().dateStringWithFormat("yyyy-MM-dd HH:mm:ss")
let myFriendPath = rootRef.child("friends").child(FeastGlobal.sharedInstance.userID)
let friendFriendsPath = rootRef.child("friends").child(friendChat.userID)
let friendInviteSync = rootRef.child("friendInviteNeedSync").child(friendChat.userID)
//
let friendsObject = [
"confirmed" : true,
"phoneNumber" : friendChat.phoneNumber,
"selfSendRequest" : true,
"timeInvited": formatterShortDate,
"userName": friendChat.userName
]
let myObject = [
"confirmed" : true,
"phoneNumber" : FeastGlobal.sharedInstance.phoneNumber,
"selfSendRequest" : false,
"timeInvited": formatterShortDate,
"userName": FeastGlobal.sharedInstance.userName
]
let friendInviteObject = [
FeastGlobal.sharedInstance.userID : FeastGlobal.sharedInstance.userName
]
queue.async {
myFriendPath.child(friendChat.userID).setValue(friendsObject)
friendFriendsPath.child(FeastGlobal.sharedInstance.userID).setValue(myObject)
friendInviteSync.setValue(friendInviteObject)
}
queue.async {
friendFriendsPath.child(FeastGlobal.sharedInstance.userID).setValue(myObject)
}
queue.async {
self.mapContactsToPresentFriends(self.feastGlobalRef.userID)
}
print("Can invite to be friend")
} else if (friendChat.statusSort == 0) {
print("Invite to Feast")
}
}
func contactPicker(_ picker: CNContactPickerViewController, didSelect contactProperty: CNContactProperty) {
let contact = contactProperty.contact
let phoneNumber = contactProperty.value as! CNPhoneNumber
print(contact.givenName)
print(phoneNumber.stringValue)
}
// Method to match contacts with Firebase db friends:
func mapContactsToPresentFriends(_ usersSyncID: String) {
// Reset the data:
self.mappedFriends.removeAll()
self.friends.removeAll()
// Use the queue (defined above) and "dispatch_async" to schedule the async actions, synchornously
// First
queue.async {
print("start 1")
self.contacts = self.findContacts()
print("end 1")
}
// Second
queue.async {
let friendsURL = self.rootRef.child("friends").child(usersSyncID) // Firebase(url: firebaseMainURL + "friends/" + usersSyncID)
var contactNumber: String?
friendsURL.observeSingleEvent(of: .value, with: { snapshot in
print("start 2")
for oneSnapshot in snapshot.children {
for oneContact in self.contacts {
for oneContactPhoneNum in oneContact.phoneNumbers {
let phoneNumber = oneContactPhoneNum.value
contactNumber = phoneNumber.stringValue
// Clean the number
let stringArray = contactNumber!.components(
separatedBy: CharacterSet.decimalDigits.inverted)
let newString = "1" + stringArray.joined(separator: "")
let firebaseFriendNumber = (oneSnapshot as AnyObject).value["phoneNumber"] as! String
print("Contacts number: " + newString)
print("Firebase number: " + firebaseFriendNumber)
if newString == firebaseFriendNumber {
print("friend added")
self.friends.append(Friend(userName: oneSnapshot.value["userName"] as! String,phoneNumber: firebaseFriendNumber, status: "Friend", statusSort: 2, name: oneContact.givenName, userID: oneSnapshot.key))
// Remove that contact
self.contacts.removeObject(oneContact)
}
}
}
}
print("end 2")
print("start 3")
// Now do the users search:
for oneContact in self.contacts {
var contactNumber: String
let phoneNumber = oneContact.phoneNumbers[0].value
contactNumber = phoneNumber.stringValue
let stringArray = contactNumber.components(
separatedBy: CharacterSet.decimalDigits.inverted)
let newString = "1" + stringArray.joined(separator: "")
//let usersURL: Firebase! = Firebase(url: firebaseMainURL + "presentUserIDUserNameByPhoneNumber/" + newString)
let usersURL = self.rootRef.child("presentUserIDUserNameByPhoneNumber").child(newString)
// Check db:
usersURL.observeSingleEvent(of: .value, with: { snapshot in
print("start 3")
if snapshot.childrenCount > 1 {
// They are users (but not your friends), and remove yourself:
if(snapshot.value!["userID"] as! String != FeastGlobal.sharedInstance.userID) {
self.friends.append(Friend(userName: snapshot.value!["userName"] as! String, phoneNumber: snapshot.key, status: "A User", statusSort: 1, name: oneContact.givenName, userID: snapshot.value!["userID"] as! String))
let userName = snapshot.value!["userName"] as! String
print("Friends name: " + userName)
}
} else {
self.friends.append(Friend(userName: "", phoneNumber: phoneNumber.stringValue, status: "Not User", statusSort: 0, name: oneContact.givenName, userID: ""))
}
// Remove that contact
self.contacts.removeObject(oneContact)
// If all done, then sort and load main screen
if self.contacts.isEmpty {
self.mappedFriends = self.friends.sorted(by: {$0.statusSort > $1.statusSort})
self.tableView.reloadData()
}
print("end 3")
})
}
})
}
}
func indexOfObject(_ object : AnyObject) -> NSInteger {
return self.indexOfObject(object)
}
func friendRequestAction() {
// TODO: Should siply be button to add friend, or request to feast.
}
// Results of search
func filterContentForSearchText(_ searchText: String, scope: String = "All") {
filterMappedFriends = mappedFriends.filter { Friend in
let categoryMatch = (scope == "All") || (Friend.status == scope)
return categoryMatch && Friend.name.lowercased().contains(searchText.lowercased())
}
tableView.reloadData()
}
// MARK: - Segues
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let indexPath = tableView.indexPathForSelectedRow {
// Ensure controller knows which dataset to pull from,
// so detail view is correct
let friendChat: Friend
if searchController.isActive && searchController.searchBar.text != "" {
friendChat = filterMappedFriends[indexPath.row]
} else {
friendChat = mappedFriends[indexPath.row]
}
// Now set the conditional cases: if a friend then chat, if user then friend request if not user then can invite them:
if segue.identifier == "showIndividualChat" {
let controller = segue.destination as! IndividualChatController
controller.friendChat = friendChat
controller.senderId = FeastGlobal.sharedInstance.userID
controller.senderDisplayName = FeastGlobal.sharedInstance.userName
}
}
}
func getFriends() {
let parametersfriend = ["fields": "name,picture.type(normal),gender"]
FBSDKGraphRequest(graphPath: "me/friends", parameters: parametersfriend).start(completionHandler: { (connection, user, requestError) -> Void in
if requestError != nil {
print(requestError)
return
}
print(user)
})
}
}
特定对象:
let friendsObject = [
"confirmed" : true,
"phoneNumber" : friendChat.phoneNumber,
"selfSendRequest" : true,
"timeInvited": formatterShortDate,
"userName": friendChat.userName
]
let myObject = [
"confirmed" : true,
"phoneNumber" : FeastGlobal.sharedInstance.phoneNumber,
"selfSendRequest" : false,
"timeInvited": formatterShortDate,
"userName": FeastGlobal.sharedInstance.userName
]
你可以附上截图或有用的东西来解决这个错误吗? – sohnryang
@sohnryang我在friendsObject和myObject字典对象上添加了错误 – Sauron
的类型不正确。根据你最后一个工作版本的Swift,他们改变了它,你的代码可能假设该对象的价值是别的。您现在需要明确地将字典值转换为您期望从中获得的值。如果你从FriendsViewController发布代码,它会告诉你如何正确投射对象 – JustinM