How to Convert React Native Objective C Project into Swift - swift

I'm developing an iOS Project which includes MongoDB Stitch and React-Native. MongoDB API is written in Swift and React Native iOS Structure is based on Objective-C. So I decided to convert Objective-C Project into Swift so that I can work with the Swift API of MongoDB and communicate with React Native via RCTBridge. So I converted the project into Swift but when I compile it in Xcode it shows a blank screen. I have created AppDelegate.swift and ProjectName-Bridging-Header.h files.
I'm using React Native Version 0.59.5
I have used this code in AppDelegate.swift file
import Foundation
import UIKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var bridge: RCTBridge!
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let jsCodeLocation: URL
jsCodeLocation = RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index.ios", fallbackResource:nil)
let rootView = RCTRootView(bundleURL: jsCodeLocation, moduleName: "REPLACE_WITH_YOUR_PROJECT_NAME", initialProperties: nil, launchOptions: launchOptions)
let rootViewController = UIViewController()
rootViewController.view = rootView
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window?.rootViewController = rootViewController
self.window?.makeKeyAndVisible()
return true
}
}

Related

Can I expose a Swift function to React Native without using Objective-C (pure swift)?

I wonder if I can expose my func navigateToLoginWidget to React Native. So that it can be triggered from RN.
I have managed to change the Objective-C template that comes with React Native to Swift like so:
import Foundation
import IBMCloudAppID
import BMSCore
import UIKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var bridge: RCTBridge!
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// initializing App ID SDK
let region = AppID.REGION_SOMEWHERE
let backendGUID = "MY_TENANT_ID_FROM_IBM"
AppID.sharedInstance.initialize(tenantId: backendGUID, region: region)
// Initializing React Native front-end with Swift instead of Obj-c template
let jsCodeLocation: URL
jsCodeLocation = RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index.js", fallbackResource:nil)
let rootView = RCTRootView(bundleURL: jsCodeLocation, moduleName: "MY_PROJECT_NAME", initialProperties: nil, launchOptions: launchOptions)
let rootViewController = UIViewController()
rootViewController.view = rootView
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window?.rootViewController = rootViewController
self.window?.makeKeyAndVisible()
return true
}
func application(_ application: UIApplication, open url: URL, options :[UIApplication.OpenURLOptionsKey : Any]) -> Bool {
return AppID.sharedInstance.application(application, open: url, options: options)
}
func navigateToLoginWidget(_ sender : Any) {
print("clicked")
AppID.sharedInstance.loginWidget?.launch(delegate: SigninDelegate)
}
}
I would normally have this function in another module called SigninDelegate.swift, but I have included it in the same class for explanatory purposes.
According to the official documentation:
Swift doesn't have support for macros so exposing it to React Native
requires a bit more setup but works relatively the same.
So yes, it is possible, but some setup is needed. Check the docs in the link above for the steps you need to follow to set it up.

iOS 13/Facebook SDK error "Unable to find a valid UIWindow"

(To forestall well-intended suggestions, yes I posted this question last week on Facebook's developer forum. No responses yet.)
TL;DR
Facebook SDK 5.8 complains at startup FBSDKLog: Unable to find a valid UIWindow.
The Main Story
In a from-scratch, one-view Xcode 11/iOS 13 project, there is no longer a default UIWindow member associated with the application. (The window per se is still around; you can see it, contained in a UIWindowScene, using the View Hierarchy Debugger in Xcode, or the Reveal app.)
FBSDK 5.8 does seem to be iOS-13-aware, and looks around for it. The relevant code is at line 498 of
https://github.com/facebook/facebook-ios-sdk/blob/master/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKInternalUtility.m.
Facebook's code iterates over the application's connectedScenes member, which for me is an empty set. How do I modify my code so that FBSDK finds the window?
Some Hacking
I tried adding the following to scene(_:willConnectTo:options:) but it seems to be too late — the FBSDKLog message has already appeared by then. (So I'm flailing...)
guard let s = (scene as? UIWindowScene) else { return }
self.window = UIWindow(windowScene: s)
The following also failed, but it was just a shot in the dark:
guard let s = (scene as? UIWindowScene) else { return }
self.window = UIWindow(frame: s.coordinateSpace.bounds)
self.window?.windowScene = s
self.window?.rootViewController = ViewController(nibName: nil, bundle: nil)
self.window?.makeKeyAndVisible()
If you don't use the new behaviour and don't mind reverting to the old way, you can try the following
Delete Application Scene Manifest key from Info.plist
Delete SceneDelegate.swift
Add var window: UIWindow?to AppDelegate.swift
import UIKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow? // <-- Here
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
// window!.makeKeyAndVisible()
return true
}
}
Add window variable to AppDelegate class
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
Assign UIWindow inside didFinishLaunchingWithOptions
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
if let window = window {
window.makeKeyAndVisible()
self.window = window
}
ApplicationDelegate.shared.application(
application,
didFinishLaunchingWithOptions: launchOptions
)
return true
}

How to create UI programmatically in Xcode 11? [duplicate]

This question already has an answer here:
Xcode 11 & iOS13, using UIKIT can't change background colour of UIViewController
(1 answer)
Closed 3 years ago.
Update: Finally got it working. See below code for SceneDelegate.swift
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = (scene as? UIWindowScene) else { return }
window = UIWindow(frame: windowScene.coordinateSpace.bounds)
window?.windowScene = windowScene
window?.rootViewController = ViewController()
window?.makeKeyAndVisible()
}
In contrast to the tutorials and the articles online, I was not able to create a working UI with the latest Xcode. This was also the case with Xcode 10, but I did not care at the time.
My steps are as follows:
Delete Main.storyboard
Delete Main from project settings
Write basic UIWindow code:
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
window?.makeKeyAndVisible()
let mainVC = ViewController()
window?.rootViewController = mainVC
return true
}
At this point I am getting an error saying cannot find the storyboard named Main in the bundle. If I go ahead and clear the entry from Info.plist, this time it complains that there are not enough characters in the storyboard name.
Any ideas?
These are the steps I followed to get UI working programmatically in Xcode 11.
1) Created a new project as usual
2) I deleted the Main.Storyboard file from the project navigator on the left-hand side.
3) In General tab I removed the Main option from the Main Interface drop-down list
4) Next, go to your Info.plist file and completely remove the Storyboard Name from the list
5) Now if you run the app, it should not crash and it should show you a black screen.
6) Next, go to the SceneDelegate.swift file and initialise your UIWindow object as usual. There is a catch here and is new in Xcode 11. You also set the windowScene property of the window object, or else it won't work.
7) Once that's all done, Go to your ViewController class and set the background colour of the view to some colour and you should be all good.
You can also use templates:
Xcode 11 Programmatic UIKit templates
Hope this helped you!!!
This works for me on Xcode 10.3 Swift 5, and Xcode 11 Swift 5.1.
On your new Xcode project, on the Info.plist file, delete the launch screen and main interface file name entries, (don't leave the entry there with an empty string)
Remove the #UIApplicationMain attribute from your AppDelegate class.
Also, this link may help you, you can find info on UIApplicationMain
https://docs.swift.org/swift-book/ReferenceManual/Attributes.html
See code below:
// Created by Juan Miguel Pallares Numa on 9/16/19.
// Copyright © 2019 Juan Miguel Pallares Numa. All rights reserved.
import UIKit
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var myViewController = ViewController()
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
window = UIWindow(frame: UIScreen.main.bounds)
window?.rootViewController = myViewController
window?.makeKeyAndVisible()
return true
}
}
import UIKit
class ViewController: UIViewController {
convenience init() {
self.init(nibName: nil, bundle: .main)
view = UIView(frame: UIScreen.main.bounds)
view.backgroundColor = UIColor(
displayP3Red: 0.0, green: 0.7, blue: 0.0, alpha: 1.0)
}
}
// call this file "main.swift"
import Foundation
import UIKit
UIApplicationMain(
CommandLine.argc, CommandLine.unsafeArgv, nil, NSStringFromClass(AppDelegate.self))

Am I doing this correctly? Swift 3 xcode loading data from firebase

The way I currently load my data is in the viewWillAppear on their specific view controllers. My question is should I load all the data on the Home/Main View Controller and pass the data that way? Or is the current way Im doing it better?
I know this is subjective, I'm loading ALOT of data.
Structure:
If you do not want the data to persist between app processes (when the app is closed the data is cleared), you can use Global Variables. When it comes to retrieving data, I suggest you to create a function in AppDelegate called retrieveFromFirebase(), containing every piece of code needed to retrieve data in your app, for all the UIViewControllers of your app. Then you should call it inside
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {}
Then, inside your function, you should assign the snapshot's value to the global variable declared earlier.
Example:
This is an example of how to setup AppDelegate.swift for this:
import UIKit
import CoreData
import Firebase
//declaration of the global variable
var username = String()
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
FIRApp.configure()
retrieveFromFirebase()
return true
}
func retrieveFromFirebase(){
// get the data from Firebase
let ref = FIRDatabase.database().reference()
ref.child("username").observe(FIRDataEventType.value, with: { snapshot in
username = snapshot.value! as! String
})
}
// other methods from AppDelegate.swift
}
And when you get to the desired ViewController, set your viewDidAppear function to this:
override func viewDidAppear(_ animated: Bool){
super.viewDidAppear(animated)
yourLabel.text = username
}
And you can just use your username anywhere in the current Module.
Hope it helps!

swift 3 error xcode 8.1 while assigning rootviewcontroller says it is a get-only property

I was migrating my project from swift 2.2 to 3.0, when I reached a point where I get this strange error, which does not allow me to set rootviewcontroller in the app delegate didfinishlaunching.
self.window?.rootViewController = self.container.resolve(DPSlideMenuController.self)!
I guess you're using this library SlideMenuControllerSwift . It would be great if you show the whole code inside the DidFinishLaunching function.
Anyway, try to do the following :
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// create viewController code...
let slideMenuController = SlideMenuController(mainViewController: mainViewController, leftMenuViewController: leftViewController, rightMenuViewController: rightViewController)
self.window?.rootViewController = slideMenuController
self.window?.makeKeyAndVisible()
return true
}
Finally fixed it. The issue was there was a var named rootViewController in one of the protocol extension.
var rootViewController: UIViewController {
return (UIApplication.shared.keyWindow?.rootViewController)!
}
Was working fine with Swift 2.2, but on swift 3 was confusing the compiler. Changed the name and the code got compiled.