I am trying to create a singleton with WebSocket functionality and I just don't know why it's not working
This is my singleton extension:
import Starscream
extension WebSocketManager: WebSocketDelegate {
func websocketDidConnect(socket: WebSocket) {
print("websocket is connected")
}
func websocketDidDisconnect(socket: WebSocket, error: NSError?) {
if let e = error {
print("websocket is disconnected: \(e.localizedDescription)")
} else {
print("websocket disconnected")
}
}
func websocketDidReceiveMessage(socket: WebSocket, text: String) {
print("Received text: \(text)")
}
func websocketDidReceiveData(socket: WebSocket, data: Data) {
print("Received data: \(data.count)")
}}
My singleton:
final class WebSocketManager: NSObject {
static let sharedInstance = WebSocketManager()
public var socket = WebSocket(url: URL(string: "ws://t-w-a.herokuapp.com/new")!)
private override init() {
super.init()
// testing connection of the socket
}
func establishConnection() {
socket.connect()
}
func closeConnection() {
socket.disconnect()
}}
When I am trying to connect the server just nothing happens.
Here is my controller:
class ChatViewController: UIViewController {
#IBOutlet weak var typeText: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
WebSocketManager.sharedInstance.establishConnection()
}}
I've found problem, I just forgot to assign socket variable with the delegate
Related
I have content that is loaded in the background.
Loading is a long running task and I want to show data as soon as it's available.
My view show loaded content and a ProgressView whenever there is more content to be expected.
struct MyListView : View
{
#MyContent
var content: [MyItem]
var body: some View
{
List
{
//...show content elements
if content.hasMoreData()
{
ProgressView().task
{
await _content.load(.end)
}
}
}
}
}
I use a custom propertyWrapper to load the data.
#propertyWrapper
struct MyContent<E> : DynamicProperty
{
final class Container<E> : ObservableObject
{
var wrappedValue : [E]
}
let container: Container<E>
var wrappedValue : [E] { container.wrappedValue }
func load() async
{
//...load more content
}
}
When the view loads, the ProgressView spins and the load function is called.
After more data has been loaded the view is refreshed. Unfortunately however the task on the ProgressView is not renewed. The load function is not called again.
I also tried wrapping the MyContent wrapper in an ObservableObject but with similar effects.
final class MyBox<E> : ObservableObject
{
#MyContent
var content: [MyItem]
func load() async
{
await _content.load(position)
await send()
}
#MainActor
private func send() async
{
objectWillChange.send()
}
}
If I look at FetchRequest which is a struct and which has a batchLimit, I think it should not be necessary to use MyBox or an ObservableObject' just to trigger and additional load` call.
How can I force the ProgressView to run the task again?
I'm using onesignal for push notifications and it was working well until the ios 14 upgrade. When I build the same app without any changes on Xcode 12, I got this warning in the console.
Notifications not accepted. You can turn them on later under your iOS
settings
There was no problem on iOS 13, it happened when I update to iOS 14.
AppDelegate.swift
import UIKit
import CoreData
import Firebase
import GoogleMobileAds
import OneSignal
import UserNotifications
import SDWebImageWebPCoder
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, OSPermissionObserver, OSSubscriptionObserver {
var window: UIWindow?
var shortcutItemToProcess: UIApplicationShortcutItem?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
FirebaseApp.configure()
GADMobileAds.sharedInstance().start(completionHandler: nil)
let onesignalInitSettings = [kOSSettingsKeyAutoPrompt: false, kOSSettingsKeyInAppLaunchURL: false]
OneSignal.initWithLaunchOptions(launchOptions,
appId: "my key is here",
handleNotificationAction: nil,
settings: onesignalInitSettings)
OneSignal.inFocusDisplayType = OSNotificationDisplayType.notification
OneSignal.promptForPushNotifications(userResponse: { accepted in
print("User accepted notifications: \(accepted)")
})
// Add your AppDelegate as an obsserver
OneSignal.add(self as OSPermissionObserver)
OneSignal.add(self as OSSubscriptionObserver)
registerForPushNotifications()
let WebPCoder = SDImageWebPCoder.shared
SDImageCodersManager.shared.addCoder(WebPCoder)
return true
}
func registerForPushNotifications() {
let notificationCenter = UNUserNotificationCenter.current()
notificationCenter.delegate = self
let readAction = UNNotificationAction(identifier: "oku", title: "Haberi Oku", options: [.foreground])
let closeAction = UNNotificationAction(identifier: "kapat", title: "Kapat", options: [])
let category = UNNotificationCategory(identifier: "etkilesim", actions: [readAction, closeAction], intentIdentifiers: [], options: [])
notificationCenter.setNotificationCategories([category])
}
func onOSPermissionChanged(_ stateChanges: OSPermissionStateChanges!) {
if stateChanges.from.status == OSNotificationPermission.notDetermined {
if stateChanges.to.status == OSNotificationPermission.authorized {
print("Thanks for accepting notifications!")
} else if stateChanges.to.status == OSNotificationPermission.denied {
print("Notifications not accepted. You can turn them on later under your iOS settings.")
}
}
}
func onOSSubscriptionChanged(_ stateChanges: OSSubscriptionStateChanges!) {
if !stateChanges.from.subscribed && stateChanges.to.subscribed {
print("Subscribed for OneSignal push notifications!")
}
}
// MARK: UISceneSession Lifecycle
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
// Called when a new scene session is being created.
// Use this method to select a configuration to create the new scene with.
// Grab a reference to the shortcutItem to use in the scene
if let shortcutItem = options.shortcutItem {
shortcutItemToProcess = shortcutItem
}
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}
func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
// Called when the user discards a scene session.
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}
extension AppDelegate: UNUserNotificationCenterDelegate {
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.alert, .sound])
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
var postId:String = ""
var postType:String = ""
if let custom = response.notification.request.content.userInfo["custom"] as? NSDictionary{
if let a = custom["a"] as? NSDictionary{
if let id = a["id"] as? String{
postId = id
}
if let type = a["rights"] as? String{
postType = type
}
}
}
if response.actionIdentifier == "oku" {
if postId != ""{
DispatchQueue.main.async(execute: {
NotificationCenter.default.post(name: NSNotification.Name("Detail"), object: nil, userInfo: ["id": postId, "type": postType])
})
completionHandler()
}
}else if response.actionIdentifier == "kapat" {
print("KAPAT")
completionHandler()
} else {
if postId != ""{
DispatchQueue.main.async(execute: {
NotificationCenter.default.post(name: NSNotification.Name("Detail"), object: nil, userInfo: ["id": postId, "type": postType])
})
completionHandler()
}
}
}
}
I solved it! :) If your app name contains non-English characters, change your Product Name under Build Settings and build it again, that's it :)
Settings
Then you can change 'Bundle display name' in info.plist.
please help me with Facebook login
I've started with putting into pod
pod 'FacebookCore'
pod 'FacebookLogin'
pod 'FacebookShare'
and then run pod install
after this i've imported this into my viewController
import UIKit
import FacebookCore
import FacebookLogin
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let loginButton = LoginButton(readPermissions: [ .publicProfile ])
loginButton.center = view.center
view.addSubview(loginButton)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
I updated info.plist with Facebook data
how Do i get user basic profile data once user has authorized app?
What goes in AppDelegate file?
thanks
Here is the code for login the Facebook by a UIButton click.
Step 1: Copy this code into your class file:
import UIKit
import FBSDKShareKit
import FBSDKLoginKit
import FBSDKCoreKit
class Facebook_loginPageViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning(){
super.didReceiveMemoryWarning()
}
#IBAction func login(_ sender: Any) {
self.facebooklogin()
}
func facebooklogin() {
let fbLoginManager : FBSDKLoginManager = FBSDKLoginManager()
fbLoginManager.logIn(withReadPermissions: ["email"], handler: { (result, error) -> Void in
print("\n\n result: \(result)")
print("\n\n Error: \(error)")
if (error == nil) {
let fbloginresult : FBSDKLoginManagerLoginResult = result!
if(fbloginresult.isCancelled) {
//Show Cancel alert
} else if(fbloginresult.grantedPermissions.contains("email")) {
self.returnUserData()
//fbLoginManager.logOut()
}
}
})
}
func returnUserData() {
let graphRequest : FBSDKGraphRequest = FBSDKGraphRequest(graphPath: "me", parameters: ["fields":"email,name"])
graphRequest.start(completionHandler: { (connection, result, error) -> Void in
if ((error) != nil) {
// Process error
print("\n\n Error: \(error)")
} else {
let resultDic = result as! NSDictionary
print("\n\n fetched user: \(result)")
if (resultDic.value(forKey:"name") != nil) {
let userName = resultDic.value(forKey:"name")! as! String as NSString?
print("\n User Name is: \(userName)")
}
if (resultDic.value(forKey:"email") != nil) {
let userEmail = resultDic.value(forKey:"email")! as! String as NSString?
print("\n User Email is: \(userEmail)")
}
}
})
}
}
Step 2: In AppDelegate add the id of Facebook:
import UIKit
import FBSDKShareKit
import FBSDKLoginKit
import FBSDKCoreKit
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
let str_URL = url.absoluteString as NSString
if str_URL.contains("fb1111111111111111")// put you id here {
return FBSDKApplicationDelegate.sharedInstance().application(
app,
open: url as URL!,
sourceApplication: options[UIApplicationOpenURLOptionsKey.sourceApplication] as! String,
annotation: options[UIApplicationOpenURLOptionsKey.annotation])
}
return FBSDKApplicationDelegate.sharedInstance().application(
app,
open: url as URL!,
sourceApplication: options[UIApplicationOpenURLOptionsKey.sourceApplication] as! String,
annotation: options[UIApplicationOpenURLOptionsKey.annotation])
}
}
Updated Code :App Delegate
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
let str_URL = url.absoluteString as NSString
if str_URL.contains("fb111111111111111"){
return FBSDKApplicationDelegate.sharedInstance().application(
app,
open: url as URL?,
sourceApplication: options[UIApplication.OpenURLOptionsKey.sourceApplication] as! String,
annotation: options[UIApplication.OpenURLOptionsKey.annotation])
}
return FBSDKApplicationDelegate.sharedInstance().application(
app,
open: url as URL?,
sourceApplication: options[UIApplication.OpenURLOptionsKey.sourceApplication] as! String,
annotation: options[UIApplication.OpenURLOptionsKey.annotation])
}
}
Step 3: put this code into `info.plist'
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>fb1111111111111111</string>
</array>
</dict>
</array>
<key>CFBundleVersion</key>
<string>2</string>
<key>FacebookAppID</key>
<string>1111111111111111</string>
<key>FacebookDisplayName</key>
<string>Together Deal</string>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>fbapi</string>
<string>fb-messenger-api</string>
<string>fbauth2</string>
<string>fbshareextension</string>
</array>
Here is the code of
1. ViewController.swift
import UIKit
import FacebookLogin
import FBSDKLoginKit
class ViewController: UIViewController {
var dict : [String : AnyObject]!
override func viewDidLoad() {
super.viewDidLoad()
//creating button
let loginButton = LoginButton(readPermissions: [ .publicProfile ])
loginButton.center = view.center
//adding it to view
view.addSubview(loginButton)
//if the user is already logged in
if let accessToken = FBSDKAccessToken.current(){
getFBUserData()
}
}
//when login button clicked
#objc func loginButtonClicked() {
let loginManager = LoginManager()
loginManager.logIn([ .publicProfile ], viewController: self) { loginResult in
switch loginResult {
case .failed(let error):
print(error)
case .cancelled:
print("User cancelled login.")
case .success(let grantedPermissions, let declinedPermissions, let accessToken):
self.getFBUserData()
}
}
}
//function is fetching the user data
func getFBUserData(){
if((FBSDKAccessToken.current()) != nil){
FBSDKGraphRequest(graphPath: "me", parameters: ["fields": "id, name, picture.type(large), email"]).start(completionHandler: { (connection, result, error) -> Void in
if (error == nil){
self.dict = result as! [String : AnyObject]
print(result!)
print(self.dict)
}
})
}
}
}
2. AppDelegate.swift
import UIKit
import FBSDKLoginKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
//added these 3 methods
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
return FBSDKApplicationDelegate.sharedInstance().application(application, didFinishLaunchingWithOptions: launchOptions)
}
func applicationWillResignActive(_ application: UIApplication) {
FBSDKAppEvents.activateApp()
}
func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
return FBSDKApplicationDelegate.sharedInstance().application(application, open: url, sourceApplication: sourceApplication, annotation: annotation)
}
func applicationDidEnterBackground(_ application: UIApplication) {
}
func applicationWillEnterForeground(_ application: UIApplication) {
}
func applicationDidBecomeActive(_ application: UIApplication) {
}
func applicationWillTerminate(_ application: UIApplication) {
}
}
Source: Facebook Login Swift 3 Tutorial
Hope this video be helpfull for you
https://youtu.be/bOS4jqRc8Io
Contents in this Video:
Facebook SDK integration tutorial with Swift lastest 2018
Xcode new project setup
Swift iOS app login with Facebook
Tutorial Facebook login feature in iOS app
Add Facebook to Swift iOS app
Facebook login in iOS app
Steps:
Create new simple Swift Xcode project
Login to facebook develop page to create the same name APP
Add login with Facebook button, login and logout methods
Modify the configure plist, create bridging header for C, configure AppDelegate,
Run the application and test with simulator
The following are the steps to follow for facebook login in ios app.
1. Create or open an application from Xcode.
2. Create an application from your facebook account and do required configuration by going through the app settings.
3. Install required pods in your project.
4. Do required configuration in your Appdelegate
5. We need to modify plist with your facebook app id that you can get from your app by logging in facebook
6. Design UI as per your requirement.
I have created an article about Facebook login implementation in iOS app using Swift 5 in detail.
You can find clear explanation here Facebook login using Swift5
I am fetching the facebook profile picture like this
let params = ["height": 300, "width": 300, "redirect": false] as [String : Any]
let graphRequest = FBSDKGraphRequest(graphPath: "me/picture", parameters: params, httpMethod: "GET")
let connection = FBSDKGraphRequestConnection()
connection.add(graphRequest, completionHandler: { (connection, result, error) in
if error == nil {
print("profile pic ************\(result)")
}
})
connection.start()
Now I need to access the profile pictures from the ablum and set those in my collectionView . I tried to set the graphPath: "me/album/profile_picture" but no luck . Could anybody give me some hints please ?
You need to find the id of the "Profile Pictures" album and request the photos for that id.
Facebook.albums(user: "me").request({ albums in
albums.first(where: { ($0["name"] as? String) == "Profile Pictures" }).flatMap({
Facebook.photos(album: $0["id"] as! String).request({ photos in
print(photos)
})
})
})
I have made an enum below to make requesting graph api paths easier.
enum Facebook: Graphable {
case albums(user: String)
case photos(album: String)
var path: String {
switch self {
case let .albums(uid):
return "\(uid)/albums"
case let .photos(aid):
return "\(aid)/photos"
}
}
var method: String {
switch self {
case .albums, .photos:
return "GET"
}
}
var params: [String : Any] {
switch self {
case .albums:
return [:]
case .photos:
return [
"height": 300,
"width": 300,
"redirect": false
]
}
}
}
Here is the protocol and extension the enum must conform to.
protocol Graphable {
var path: String { get }
var method: String { get}
var params: [String : Any] { get }
}
extension Graphable {
typealias JSON = [String:Any]
func request(_ handler: #escaping ([JSON]!) -> (), failure: #escaping (Error) -> () = { print($0) }) {
let connection = FBSDKGraphRequestConnection()
let request = FBSDKGraphRequest(
graphPath: path,
parameters: params,
httpMethod: method
)
connection.add(request) {
_ = $0.1.map ({ handler(($0 as? JSON)?["data"] as? [JSON]) }) ??
$0.2.map ({ failure($0) })
}
connection.start()
}
}
I got my answer like this :
import FBSDKCoreKit
import SwiftyJSON
func getFBAlbumID() {
let graphRequest = FBSDKGraphRequest(graphPath: "me/albums", parameters: nil, httpMethod: "GET")
let connection = FBSDKGraphRequestConnection()
connection.add(graphRequest, completionHandler: { (connection, result, error) in
if error == nil
let dictionary = JSON(result)
// print("albums ID are **************\(dictionary)")
if let data = dictionary["data"].array {
print("data of profilePicture ******* \(data)")
if let dict = data.first(where: { ($0["name"].string ) == "Profile Pictures" }) {
let id = dict["id"].string
print("my desired id : ********* \(id)")
self.getFBAlbumPhoto(albumID: id!)
}
}
}
})
connection.start()
}
func getFBAlbumPhoto(albumID: String) {
let params = [ "height": 300, "width": 300, "redirect": false] as [String : Any]
let graphRequest = FBSDKGraphRequest(graphPath: "\(albumID)/photos?fields=source", parameters: params, httpMethod: "GET")
let connection = FBSDKGraphRequestConnection()
connection.add(graphRequest, completionHandler: { (connection, result, error) in
if error == nil {
//print(result)
let dictionary = JSON(result)
print("result are **************\(dictionary)")
}
})
connection.start()
}
Here I am grabbing the ID of the particular album I desire and then make another call to get the photos of that album. Here I am calling a function from inside another function. If someone can help me to write the code in more Swift way that would be helpful, like using closure. Thanks.
I'm using Alamofire for requests and i'm using swiftyjson for json parsing.
I need define global variables for other view controllers.
I have this code:
import UIKit
import Alamofire
import SwiftyJSON
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
struct Settings {
static var registration_url = String();
static var login_url = String();
}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
Alamofire.request("http://localhost/settings.php").responseJSON { response in
if response.result.isSuccess {
let json = JSON(data: response.data!);
Settings.registration_url = json["registration_url"].stringValue;
Settings.login_url = json["login_url"].stringValue;
} else {
Settings.registration_url = "http://localhost/register.php";
Settings.login_url = "http://localhost/login.php";
}
}
print(Settings.registration_url);
print(Settings.login_url)
return true
}
}
I'm checking debug window, and print(Settings.registration_url); is looks blank
Why?
Thanks. Sorry for my poor english.
Your Settings structure is not global. You need to define it outside the class for it to be global:
struct Settings {
static var registration_url = String();
static var login_url = String();
}
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
Alamofire.request("http://localhost/settings.php").responseJSON { response in
if response.result.isSuccess {
let json = JSON(data: response.data!);
Settings.registration_url = json["registration_url"].stringValue;
Settings.login_url = json["login_url"].stringValue;
} else {
Settings.registration_url = "http://localhost/register.php";
Settings.login_url = "http://localhost/login.php";
}
}
print(Settings.registration_url);
print(Settings.login_url)
return true
}
}