Composing tweet in Twitterkit since Xcode 9 with Swift 4 & IOS 11 - ios11

Since the upgrade to Xcode 9 and Swift 4, I've been quite busy in getting my apps back working again. But I'm still struggling with getting my tweet composer to work. In Xcode 8 this was still working fine...
case "Twitter":
if (Twitter.sharedInstance().sessionStore.hasLoggedInUsers()) {
// App must have at least one logged-in user to compose a Tweet
let composer = TWTRComposerViewController.emptyComposer()
UIApplication.shared.keyWindow?.rootViewController?.present(composer, animated: true, completion: nil)
} else {
// Log in, and then check again
Twitter.sharedInstance().logIn { session, error in
if session != nil { // Log in succeeded
let composer = TWTRComposerViewController.emptyComposer()
UIApplication.shared.keyWindow?.rootViewController?.present(composer, animated: true, completion: nil)
} else {
let alert = UIAlertController(title: "No Twitter Accounts Available", message: "You must log in before presenting a composer.", preferredStyle: .alert)
UIApplication.shared.keyWindow?.rootViewController?.present(alert, animated: false, completion: nil)
}
}
}
Is what I now litterly copy pasted from the Twitter kit website and adjusted because I have my sharing functions all in a seperate class.
When this piece of code is started, my Twitter application is being opened, and the authenticatin screen is opened as what I kind of expect:
Authenticating
When I connect, it shows me quickly my timeline, and than just goes back to my app. Without composing window...
Anyone an idea?

Problem solved with adding this in the AppDelegate:
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
let handled:Bool = true
Twitter.sharedInstance().application(app, open: url, options: options)
return handled
}

I am just confused by two methods. As soon as using the wrong method, twitter login appears, enter username and password and click done and login page appears again. That's a infinity loop.
open func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
return TWTRTwitter.sharedInstance().application(app, open: url, options: options)
}
func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
return TWTRTwitter.sharedInstance().application(application, open: url, options: [:])
}
Don't use the second one! Use the first one!

Related

Only append NEW project to collectionview (Firebase/Firestore)

On an app Im working on, users are able to upload projects by selecting an "upload project" button. Selecting this button triggers a segue to a screen where the user can now input their information for the project. Once the information is filled in and users select "upload", the screen dismisses itself, returning the user to their profile. The problem is that when a user returns to the profile screen, the project they just uploaded does not show in the collection view. it only shows the projects that were downloaded when the user first viewed their profile.
To try and fix this, I added a snapshot listener. The problem with this is: It loads the new project in, but in return, it loads every project twice. How can I set it up to where only the new project is appended, instead of every project being added again?
func setUserProjects(){
let uid = Auth.auth().currentUser?.uid
let db = Firestore.firestore()
let docRef = db.collection("projects")
docRef.whereField("uid", isEqualTo: uid!).getDocuments { (snapshot, err) in
if let err = err {
print("Error:\(err)")
} else {
for document in snapshot!.documents {
var dictionary = document.data()
let project = Project(dictionary: dictionary as [String: AnyObject])
project.id = document.documentID
self.userProjects.append(project)
self.userProjects.uniqued()
}
}
self.projectsCollectionView.reloadData()
}
docRef.whereField("uid", isEqualTo: uid!).addSnapshotListener { snapshot, err in
if let err = err {
print("Error:\(err)")
} else {
for document in snapshot!.documents {
var dictionary = document.data()
let project = Project(dictionary: dictionary as [String: AnyObject])
project.id = document.documentID
///only append the project if it's not already added
if !self.userProjects.contains(project) {
self.userProjects.append(project)
}
}
}
}
}

Retrieve data from array in another function

I am trying to retrieve the data set in an array in one function, in a different function. I appended the data i want into the OtherUserArray in the
createNewConversation function. However when i try the retrieve this data in the sendMessage function, it prints an empty array.
import MessageKit
import InputBarAccessoryView
import FirebaseAuth
import Firebase
import Foundation
final class DatabaseManager {
static let shared = DatabaseManager()
var foundOtherUser:String?
var OtherUserArray = [String]()
}
extension DatabaseManager {
// create a new conversation with target user, uid and first sent message
public func createNewConversation(with otherUserUid: String, name: String, firstMessage: Message, completion: #escaping(Bool) -> Void) {
let db = Firestore.firestore()
let CurrentUser = Auth.auth().currentUser?.uid
let defaults = UserDefaults.standard
defaults.set(CurrentUser, forKey: "uid")
guard let currentUid = UserDefaults.standard.string(forKey: "uid"), let currentName = UserDefaults.standard.string(forKey: "usersFullname") else {
return
}
let messageDate = firstMessage.sentDate
let dateString = MessageViewController.dateFormatter.string(from: messageDate)
var message = ""
let conversationId = firstMessage.messageId
let newConversationData: [String:Any] = [
"id": conversationId,
"other_user-uid": otherUserUid,
"name": name,
"latest-message": [
"date": dateString,
"message": message,
"is-read": false
]
]
// save other user uid to global var
OtherUserArray.append(otherUserUid)
}
}
}
public func sendMessage(to conversation: String, name: String, newMessage: Message, completion: #escaping(Bool) -> Void) {
// update the latest message
print(self.OtherUserArray)
}
The problem is not where you access self.OtherUserArray, but when you access it.
Data is loaded from Firebase asynchronously, while the rest of you code typically runs synchronously. By the time the print(self.OtherUserArray) in your sendMessage runs, the OtherUserArray.append(otherUserUid) hasn't been executed yet, so the array in empty. You can most easily verify this by running the code in a debugger and setting breakpoints on those like, or by adding print statements and checking the order of their output.
For examples of this, as well as how to solve the problem, see these previous questions:
Why I couldn't assign fetched values from Firestore to an array in Swift?
Is Firebase getDocument run line by line?
Storing asynchronous Cloud Firestore query results in Swift
How do I save data from cloud firestore to a variable in swift?
Why are print statements not executing in correct order?? Am I crazy or is Xcode?
Get all documents at once in a completion handler with getDocuments in Firestore

Unable to read or right data to/ from Firestore SwiftUI

I've setup Firestore DB and wanted to test it. However I was unable neither read or wright data to it. Here is what console shows on connection status to Firebase.
Debug Console:
2020-11-19 17:58:49.802849+0300 Demo [813:165300] 6.34.0 - [Firebase/Analytics][I-ACS023007] Analytics v.60900000 started
2020-11-19 17:58:49.803819+0300 Demo [813:165300] 6.34.0 - [GoogleUtilities/AppDelegateSwizzler][I-SWZ001014] App Delegate does not conform to UIApplicationDelegate protocol.
2020-11-19 17:58:49.804498+0300 Demo [813:165300] 6.34.0 - [Firebase/Analytics][I-ACS023008] To enable debug logging set the following application argument: -FIRAnalyticsDebugEnabled (see https://help.apple.com/xcode/mac/8.0/#/dev3ec8a1cb4)
2020-11-19 17:58:50.586054+0300 Demo [813:165306] 6.34.0 - [Firebase/Analytics][I-ACS800023] No pending snapshot to activate. SDK name: app_measurement
2020-11-19 17:58:51.138985+0300 Demo [813:165306] 6.34.0 - [Firebase/Analytics][I-ACS023012] Analytics collection enabled
2020-11-19 17:58:51.139362+0300 Demo [813:165306] 6.34.0 - [Firebase/Analytics][I-ACS023220] Analytics screen reporting is enabled. Call +[FIRAnalytics logEventWithName:FIREventScreenView parameters:] to log a screen view event. To disable automatic screen reporting, set the flag FirebaseAutomaticScreenReportingEnabled to NO (boolean) in the Info.plist
2020-11-19 17:58:51.850205+0300 Demo [813:165012] [AXRuntimeCommon] This class 'SwiftUI.AccessibilityNode' is not a known serializable element and returning it as an accessibility element may lead to crashes
Also Firebase it self shows that I had some reads in stats.
I stuck and don't understand what important part I didn't do in order to start implementing Firebase use. Will appreciate any help or suggestion.!
I used several methods to initiate Firebase in SwiftUI.
This one:
import SwiftUI
import Firebase
#main
struct DemoApp: App {
init() {
FirebaseApp.configure()
}
var body: some Scene {
WindowGroup {
ContentView()
.onOpenURL(perform: { url in
Auth.auth().canHandle(url)
})
}
}
Also tried with DelegateAdaptor:
#main
struct DemoApp: App {
#UIApplicationDelegateAdaptor(AppDelegate.self) var delegate
appDelegate
init() {
FirebaseApp.configure()
}
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
class AppDelegate: NSObject, UIApplicationDelegate {
func application(_ application: UIApplication,didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
print("Application is starting up. ApplicationDelegate didFinishLaunchingWithOptions.")
return true
}
}
To test writing to:
func letE() {
let db = Firestore.firestore()
db.collection("wine").addDocument(data: ["Cool" : 2017])
}
And to fetch an array
private var db = Firestore.firestore()
func fetchData() {
db.collection("collection").document("document")
.addSnapshotListener { documentSnapshot, error in
guard let document = documentSnapshot else {
print("Error fetching document: \(error!)")
return
}
guard let data = document.data()!["array name"] else {
print("Document data was empty.")
return
}
print(data)
}
And like this:
func getData(){
db.collection("skills").getDocuments() { (querySnapshot, err) in
if let err = err {
print("Error getting documents: \(err)")
} else {
for document in querySnapshot!.documents {
print("\(document.documentID) => \(document.data())")
}
}
Hello, Peter! I was trying to come to solving this problem from different angels but still no luck.
Basically I am trying to perform wright operation
It goes like this
#main
struct DemoApp: App {
init() {
FirebaseApp.configure()
}
var body: some Scene {
WindowGroup {
ContentView()
.onOpenURL(perform: { url in
Auth.auth().canHandle(url)
})
}
}
}
func addData() {
//
let db = Firestore.firestore()
//
db.collection("wine").addDocument(data: ["Test":100])
}
Then i press Build.
From my understanding that already should create collection "Wine" with autogenerated Document with contains field "Test" with value "100"
But once again nothing happens on the firebase side.
The Debug console
2021-01-26 16:22:21.907902+0300 Demo [27616:342494] 6.34.0 - [Firebase/Analytics][I-ACS023007] Analytics v.60900000 started
2021-01-26 16:22:21.908067+0300 Demo [27616:342494] 6.34.0 - [Firebase/Analytics][I-ACS023008] To enable debug logging set the following application argument: -FIRAnalyticsDebugEnabled (see https://help.apple.com/xcode/mac/8.0/#/dev3ec8a1cb4)
2021-01-26 16:22:21.934626+0300 Demo [27616:342498] 6.34.0 - [GoogleUtilities/AppDelegateSwizzler][I-SWZ001014] App Delegate does not conform to UIApplicationDelegate protocol.
2021-01-26 16:22:21.979114+0300 Demo [27616:342490] [] nw_protocol_get_quic_image_block_invoke dlopen libquic failed
2021-01-26 16:22:21.994921+0300 Demo [27616:342490] 6.34.0 - [Firebase/Analytics][I-ACS800023] No pending snapshot to activate. SDK name: app_measurement
2021-01-26 16:22:22.000217+0300 Demo [27616:342490] 6.34.0 - [Firebase/Analytics][I-ACS023012] Analytics collection enabled
2021-01-26 16:22:22.000724+0300 Demo [27616:342490] 6.34.0 - [Firebase/Analytics][I-ACS023220] Analytics screen reporting is enabled. Call +[FIRAnalytics logEventWithName:FIREventScreenView parameters:] to log a screen view event. To disable automatic screen reporting, set the flag FirebaseAutomaticScreenReportingEnabled to NO (boolean) in the Info.plist
2021-01-26 16:22:22.032550+0300 Demo [27616:342197] [LayoutConstraints] Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this:
(1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it.
(
"<NSLayoutConstraint:0x60000341ce60 'BIB_Trailing_CB_Leading' H:[_UIModernBarButton:0x7fb0e7d16480]-(6)-[_UIModernBarButton:0x7fb0e7d0a710'Skills'] (active)>",
"<NSLayoutConstraint:0x60000341ceb0 'CB_Trailing_Trailing' _UIModernBarButton:0x7fb0e7d0a710'Skills'.trailing <= _UIButtonBarButton:0x7fb0e7d10cb0.trailing (active)>",
"<NSLayoutConstraint:0x60000341dc20 'UINav_static_button_horiz_position' _UIModernBarButton:0x7fb0e7d16480.leading == UILayoutGuide:0x600002e54ee0'UIViewLayoutMarginsGuide'.leading (active)>",
"<NSLayoutConstraint:0x60000341dc70 'UINavItemContentGuide-leading' H:[_UIButtonBarButton:0x7fb0e7d10cb0]-(0)-[UILayoutGuide:0x600002e54e00'UINavigationBarItemContentLayoutGuide'] (active)>",
"<NSLayoutConstraint:0x60000347eda0 'UINavItemContentGuide-trailing' UILayoutGuide:0x600002e54e00'UINavigationBarItemContentLayoutGuide'.trailing == _UINavigationBarContentView:0x7fb0e7e0f7e0.trailing (active)>",
"<NSLayoutConstraint:0x60000341e3f0 'UIView-Encapsulated-Layout-Width' _UINavigationBarContentView:0x7fb0e7e0f7e0.width == 0 (active)>",
"<NSLayoutConstraint:0x60000347e9e0 'UIView-leftMargin-guide-constraint' H:|-(0)-[UILayoutGuide:0x600002e54ee0'UIViewLayoutMarginsGuide'](LTR) (active, names: '|':_UINavigationBarContentView:0x7fb0e7e0f7e0 )>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x60000341ce60 'BIB_Trailing_CB_Leading' H:[_UIModernBarButton:0x7fb0e7d16480]-(6)-[_UIModernBarButton:0x7fb0e7d0a710'Skills'] (active)>
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKitCore/UIView.h> may also be helpful.
The changed Debug Console outcome presented is because I've setup authorised access and it does work. I can create user and then perform login with crated login and password. All users do show up on the Firebase console.

Swift EKCalendar not persisting

I can create a new calendar and save it with the following function:
func createCalendarForUser() {
let sourcesInEventStore = self.eventStore.sources
//works but doesn't persist
let subscribedSourceIndex = sourcesInEventStore.index {$0.title == "Subscribed Calendars"}
if let subscribedSourceIndex = subscribedSourceIndex {
let userCalendar = EKCalendar(for: .event, eventStore: self.eventStore)
userCalendar.title = "newCalendar"
userCalendar.source = sourcesInEventStore[subscribedSourceIndex]
do {
try self.eventStore.saveCalendar(userCalendar, commit: true)
print("calendar creation successful")
} catch {
print("cal \(userCalendar.source.title) failed : \(error)")
}
}
}
This functions great while the app is open and running. I can save events to them, i can see them in my local calendar, and life is good. However, once the app is terminated and goes into the background the calendars disappear, along with any events created in them. I've tried saving the calendar to different sources other then the Subscribed Calendars source but when i do that the calendars wont even save in the first place. Heres one of the attempts at using the local source:
func createCalendarForUser() {
let sourcesInEventStore = self.eventStore.sources
//never saves calendar
let localSourceIndex = sourcesInEventStore.index {$0.sourceType == .local}
if let localSourceIndex = localSourceIndex {
let userCalendar = EKCalendar(for: .event, eventStore: self.eventStore)
userCalendar.title = "newCalendar"
userCalendar.source = sourcesInEventStore[localSourceIndex]
do {
try self.eventStore.saveCalendar(userCalendar, commit: true)
print("creating new calendar successful")
} catch {
print("creating new calendar failed : \(error)")
}
}
}
I also tried this method :
func createCalendarForUser() {
let sourcesInEventStore = self.eventStore.sources
//doesnt work
let userCalendar = EKCalendar(for: .event, eventStore: self.eventStore)
userCalendar.title = "newCalendar"
userCalendar.source = sourcesInEventStore.filter{
(source: EKSource) -> Bool in
source.sourceType.rawValue == EKSourceType.local.rawValue
}.first!
do {
try self.eventStore.saveCalendar(userCalendar, commit: true)
print("creating new calendar succesful")
} catch {
print("creating new calendar failed : \(error)")
}
}
As metioned here as mentioned here https://www.andrewcbancroft.com/2015/06/17/creating-calendars-with-event-kit-and-swift/
Has anyone else come across this problem?
The blog post you link do does two things when it saves the calendar, it uses the saveCalendar(, commit) method to save the calendar to the event store, and then also saves the identifier for the calendar to user defaults so that it can be retrieved at a later time:
NSUserDefaults.standardUserDefaults().setObject(newCalendar.calendarIdentifier, forKey: "EventTrackerPrimaryCalendar")
You're doing the first, but not the second step, so your calendars will be persisting in the store, but you're not keeping the information needed to retrieve them in the future.

How to share multiple urls to Facebook on iOS 6

Hi I'm using the facebook share sheet on SDK 3.1 and it works except when I try to share 2 urls it crashes.
NSArray* urls = [NSArray arrayWithObjects:#"http://google.com", #"http://yahoo.com", nil];
BOOL displayedNativeDialog = [FBNativeDialogs presentShareDialogModallyFrom:self
initialText: #"hellooo"
images: nil
urls: urls
handler: ^(FBNativeDialogResult result, NSError *error) {
if (error) {
NSLog(#"handler error:%#, %#", error, [error localizedDescription]);
} else {
if (result == FBNativeDialogResultSucceeded)
{
NSLog(#"handler success");
}
else
{
NSLog(#"handler user cancel");
}
}
}];
Result:
-[__NSCFConstantString isMusicStoreURL]: unrecognized selector sent to instance 0x3d23e8
* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFConstantString isMusicStoreURL]: unrecognized selector sent to instance 0x3d23e8'
I believe that the NSArray of Urls it is taking is expecting NSURLs, not NSStrings. You can use the static URLWithString to get the NSURLs for the array.

Resources