NavigationTitle blink - ios

If app is killed and user click on push notification app takes it directly to the respective screen(detail screen) but before pushing to the detail screen we push to the list screen.When user click on back button of detail screen navigation title of list screen comes empty for a sec then gets correctly.What could be the reason.
switch(model!.action[1].lowercased()){
case "profile":
NotificationUtils.sharedInstance.moveToDirectoryModuleWithLTDS() //Will shift to Directory module
NotificationUtils.sharedInstance.moveToLocationList(false)
NotificationUtils.sharedInstance.moveToLocation(Guid(locID),rightPanel: false, needAnimation: false) //Move to department detail screen with Info tab selected
hideLoader() //Will stop loading indicator
break
}
func moveToLocationList(_ animate: Bool = true) {
hideNavigationTitle() //This function is used to clear the back button title.
let dropVC = DepartmentViewController(nibName: "DepartmentViewController", bundle: nil)
dropVC.employeeGroupInfo = EmployeeGroupInfo.locationInfo
self.pushWithDelayToVC(dropVC, animation: animate)
}
func pushWithDelayToVC(_ viewController:UIViewController,animation:Bool = true)
{
let appDelegate = UIApplication.shared.delegate as! AppDelegate
AppDelegate.removeUserProfileSetupScreens()
self.removeComposer { () -> Void in
UIUtils.pushViewWhenHideBottom((appDelegate.tabBarController.selectedViewController as! UINavigationController).visibleViewController!, anotherVC: viewController, needAnimation: animation)
self.hideSidePanel()
}
}
func removeComposer(_ completion: #escaping (() -> Void))
{
let appDelegate = UIApplication.shared.delegate as! AppDelegate
if let selectedController = appDelegate.tabBarController.selectedViewController
{
if let selectNavController = selectedController as? UINavigationController
{
if let visibleController = selectNavController.visibleViewController
{
if (NSStringFromClass(type(of: visibleController)) == "MFMailComposeInternalViewController" || NSStringFromClass(type(of: visibleController)) == "CKSMSComposeController" || NSStringFromClass(type(of: visibleController)) == "PLUICameraViewController" || NSStringFromClass(type(of: visibleController)) == "UIAlertController")
{
visibleController.dismiss(animated: false, completion: { () -> Void in
completion()
return
})
}
else
{
completion()
}
}
else { completion() }
}
else { completion()}
}
else { completion() }
}
And code of viewWillAppear is :
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if employeeGroupInfo == EmployeeGroupInfo.departmentInfo {
UIUtils.setTitleFontWhiteOnNavigationController(viewCtrl: self, titleStr: AppMessage.EDByDepartment)
} else if employeeGroupInfo == EmployeeGroupInfo.locationInfo {
UIUtils.setTitleFontWhiteOnNavigationController(viewCtrl: self, titleStr: AppMessage.EDByLocation)
} else if employeeGroupInfo == EmployeeGroupInfo.teamInfo {
UIUtils.setTitleFontWhiteOnNavigationController(viewCtrl: self, titleStr: AppMessage.EDMoreByTeamsMob)
}
self.tabBarController?.tabBar.isHidden = false
}
public class func setTitleFontWhiteOnNavigationController(viewCtrl: UIViewController, titleStr: String, needBorder: Bool = true,needTitleImage: Bool = false)
{
viewCtrl.extendedLayoutIncludesOpaqueBars = true
viewCtrl.navigationController?.navigationBar.isTranslucent = false
viewCtrl.navigationController?.navigationBar.barTintColor = UIColor.LTColor()
// Set navigation bar background color
viewCtrl.navigationController?.navigationBar.tintColor = UIColor.white
viewCtrl.navigationController?.navigationBar.titleTextAttributes = [NSFontAttributeName: UIFont.boldSystemFont(ofSize: 18.0),NSForegroundColorAttributeName: UIColor.white]
if needTitleImage {
setImageWithTitle(viewCtrl: viewCtrl,titleStr: titleStr)
}
else {
viewCtrl.title = titleStr
}
if needBorder
{
//Used to hide shadow line in navigation bar by Nikhil
viewCtrl.navigationController?.navigationBar.setBackgroundImage(nil, for: UIBarMetrics.default)
viewCtrl.navigationController?.navigationBar.shadowImage = nil
}
else
{
//Used to hide shadow line in navigation bar by Nikhil
viewCtrl.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: UIBarMetrics.default)
viewCtrl.navigationController?.navigationBar.shadowImage = UIImage()
}
}

Related

Calling Present on View Fails with modally active controller error

When calling present on a hamburger menu, it succeeds on the first load but fails on the second.
Once the app launches you log in. It then calls the listener to perform actions after log in. You can click the burger menu on the left and it works. Now, if you log out, log back in and then hit the burger menu again, it throws the error Application tried to present modally an active controller HomePageViewController. It seems as if something was loaded correctly when the app first loads and it's trying to do it again which is causing to fail. I can't figure out what. Any help would be appreciated here. I've included AppDelegate.swift and AppController.swift which both are relevant here.
#objc func burgerButtonAction(_ sender: Any) {
present(SideMenuManager.default.menuLeftNavigationController!, animated: true, completion: nil)
}
AppDelegate.swift
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
AppController.sharedInstance.enableCognitoClientWithAuthentication()
// setup logging
self.window = UIWindow(frame: UIScreen.main.bounds)
AppController.sharedInstance.launchInWindow(aWindow: self.window)
let signedIn = AWSMobileClient.sharedInstance().isSignedIn
self.navigationController = UINavigationController()
if !signedIn {
navigationInit()
} else {
AppController.sharedInstance.showLoggedInStateAndReturn(true)
}
//pool.delegate = self
return true
}
func navigationInit() {
let loginViewController = LoginViewController()
self.navigationController!.pushViewController(loginViewController, animated: false)
}
AppController.swift
class AppController: NSObject {
func launchInWindow(aWindow: UIWindow?){
self.window = aWindow
self.initializeSDKs()
self.globalCustomization()
self.AWSUnAuthedClient.apiKey = Constants.APIKeys.AWSAPIKey
DispatchQueue.main.async {
self.window!.rootViewController = self.createAndReturnRootVC()
self.window!.makeKeyAndVisible()
}
}
private func createAndReturnRootVC() -> UIViewController {
// Auth Status
let cognitoAuth = AWSCognitoAuth.default()
if AWSMobileClient.sharedInstance().isSignedIn {
return self.showLoggedInStateAndReturn(true)!
} else {
let loginVC = LoginViewController()
return loginVC
}
}
func enableCognitoClientWithAuthentication() {
AWSMobileClient.sharedInstance().initialize { (userState, error) in
if let userState = userState {
print("UserState: \(userState.rawValue)")
}else if let error = error {
print("error: \(error.localizedDescription)")
}
}
AWSMobileClient.sharedInstance().addUserStateListener(self) { (userState, info) in
switch (userState) {
case .signedOut:
// user clicked signout button and signedout
print("user signed out")
self.window?.rootViewController = LoginViewController()
case .signedOutUserPoolsTokenInvalid:
print("need to login again.")
AppController.sharedInstance.showLogin()
//Alternatively call .showSignIn()
case .signedIn:
self.registerForPush()
self.hydrateLocalUser()
self.launchInWindow(aWindow: self.window)
// DispatchQueue.main.async {
// self.window!.rootViewController = self.createAndReturnRootVC()//self.showLoggedInStateAndReturn(true)
// self.window!.makeKeyAndVisible()
// }
default:
print(userState)
print("unsupported")
}
}
}
#discardableResult func showLoggedInStateAndReturn(_ shouldReturn: Bool) -> UIViewController? {
//AppController.sharedInstance.enableCognitoClientWithAuthentication()
//self.registerForPush()
self.tabBarController = ESTabBarController()
//tabBarController.delegate = delegate
self.tabBarController?.title = "Irregularity"
self.tabBarController?.tabBar.shadowImage = UIImage.image(with: UIColor("FFFFFF", alpha: 0.0)!)
self.tabBarController?.tabBar.backgroundImage = UIImage.image(with: UIColor("2A2A27")!)
self.tabBarController?.shouldHijackHandler = {
tabbarController, viewController, index in
if index == 1 {
return true
}
return false
}
self.tabBarController?.didHijackHandler = {
[weak tabBarController] tabbarController, viewController, index in
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
let newProjectNavCon = UINavigationController(rootViewController: NewProjectViewController())
newProjectNavCon.hero.isEnabled = true
newProjectNavCon.setNavigationBarHidden(true, animated: false)
newProjectNavCon.hero.navigationAnimationType = .fade
tabBarController?.present(newProjectNavCon, animated: true, completion: nil)
}
}
let centerVC = UINavigationController(rootViewController: HomeViewController())
let v1 = centerVC
let v2 = BaseViewController()
let v3 = UINavigationController(rootViewController: ProfileViewController())
v1.tabBarItem = ESTabBarItem.init(TabBarBouncesContentView(), title: "Projects", image: UIImage(named: "tabBarTruck"), selectedImage: UIImage(named: "tabBarTruck"))
v2.tabBarItem = ESTabBarItem.init(TabBarIrregularityContentView(), title: nil, image: UIImage(named: "tabBarPlusButton"), selectedImage: UIImage(named: "tabBarPlusButton"))
v3.tabBarItem = ESTabBarItem.init(TabBarBouncesContentView(), title: "Profile", image: UIImage(named: "tabBarProfile"), selectedImage: UIImage(named: "tabBarProfile"))
self.tabBarController?.setViewControllers([v1, v2, v3], animated: true)
if shouldReturn {
return self.tabBarController
} else {
self.window?.rootViewController = self.tabBarController
return nil
}
}
}

What is the best way to present lock screen in iOS?

I wondering the best way to present lock screen in iOS(swift).
ex) If the user presses the home button or receives a call, I want to display the lock screen when user re-enter the app.
So, I tried this way.
func applicationWillResignActive(_ application: UIApplication) {
guard let passcodeManageView = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "passcodeManageView") as? PasscodeManageViewController else { return }
if let window = self.window, let rootViewController = window.rootViewController {
var currentController = rootViewController
while let presentController = currentController.presentedViewController {
currentController = presentController
}
currentController.present(passcodeManageView, animated: true, completion: nil)
}
}
Actually it works pretty well.
However, if the alert window is displayed, it does not work normally.
How can I fixed it? (Sorry for my eng.)
Alert views are always an issue in these cases. A quick solution might be to check if alert view is presented and dismiss it. I played with the following:
func showOverlayController(currentController: UIViewController) {
currentController.present(OverlayViewController(), animated: true, completion: nil)
}
if let window = UIApplication.shared.keyWindow, let rootViewController = window.rootViewController {
var currentController = rootViewController
while let presentController = currentController.presentedViewController {
guard presentController as? UIAlertController == nil else {
presentController.dismiss(animated: false) {
showOverlayController(currentController: currentController)
}
return
}
currentController = presentController
}
showOverlayController(currentController: currentController)
}
Putting aside animations and all this still seems very bad because I suspect if if a view controller inside navigation controller or tab bar controller (or any other type of content view controller) would present an alert view this issue would again show itself. You could use the same logic of finding a top controller to always present alert view on top controller to overcome this.
So I moved to another way which is I would rather change the root view controller instead of presenting an overlay. So I tried the following:
static var currentOverlay: (overlay: OverlayViewController, stashedController: UIViewController)?
static func showOverlay() {
guard currentOverlay == nil else { return }
guard let currentController = UIApplication.shared.keyWindow?.rootViewController else { return }
let overlay: (overlay: OverlayViewController, stashedController: UIViewController) = (overlay: OverlayViewController(), stashedController: currentController)
self.currentOverlay = overlay
UIApplication.shared.keyWindow?.rootViewController = overlay.overlay
}
static func hideOverlay() {
guard let currentOverlay = currentOverlay else { return }
self.currentOverlay = nil
UIApplication.shared.keyWindow?.rootViewController = currentOverlay.stashedController
}
It works great... Until alert view is shown again. So after a bit of an inspection I found out that in case of alert views your application has multiple windows. It makes sense an alert would create a new window over the current one but I am unsure how did anyone think it would be intuitive or that it would in any possible way make sense that you are presenting alert view. I would then expect something like UIApplication.shared.showAlert(alert) but let's put this stupidity aside.
The only real solution I see here is to add a new window for your dialog. To do that you could look around the web. What seems to work for me is the following:
static var currentOverlayWindow: (overlay: OverlayViewController, window: UIWindow, previousWindow: UIWindow)?
static func showOverlay() {
guard currentOverlay == nil else { return }
guard let currentWindow = UIApplication.shared.keyWindow else { return }
let overlay: (overlay: OverlayViewController, window: UIWindow, previousWindow: UIWindow) = (overlay: OverlayViewController(), window: UIWindow(frame: currentWindow.bounds), previousWindow: currentWindow)
self.currentOverlayWindow = overlay
overlay.window.backgroundColor = UIColor.black
overlay.window.rootViewController = overlay.overlay
overlay.window.windowLevel = UIWindowLevelAlert + 1
overlay.window.makeKeyAndVisible()
}
static func hideOverlay() {
guard let currentOverlayWindow = currentOverlayWindow else { return }
self.currentOverlay = nil
currentOverlayWindow.window.isHidden = true
currentOverlayWindow.previousWindow.makeKeyAndVisible()
}
Just to fill in the gaps. What I used as an overlay view controller:
class OverlayViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let button = UIButton(frame: CGRect(x: 12.0, y: 100.0, width: 150.0, height: 55.0))
button.setTitle("Dismiss", for: .normal)
view.addSubview(button)
button.addTarget(self, action: #selector(onButton), for: .touchUpInside)
}
#objc private func onButton() {
AppDelegate.hideOverlay()
// self.dismiss(animated: true, completion: nil)
}
}

Programmatically advance UIPageViewController - Swift

This is my first attempt at an IOS app, and I have no experience with swift, and a lot of the code is borrowed from the web and edited.
I am trying to create a set of slides. I go from the main Landing page to another View Controller, TestVC, that runs the slides. The landing page and the slides work. I can swipe back and forth. I am now trying to add a timer so that the slides auto advance every 5 or so seconds.
I believe that the code that needs to be run is:
pageViewController.setViewControllers(varPageVC, direction: UIPageViewControllerNavigationDirection.forward, animated: true, completion: nil)
I get an error :
test.swift:31:9: Ambiguous reference to member 'pageViewController(_:viewControllerBefore:)'.
I do not know how to interpret this error and move forward. The error is triggered in the test.swift, where a timer calls a function that tries to advance the slide. Advise is appreciated. If I am doing it wrong, please point me in the appropriate direction.
The landing page has a button, that opens a ViewController testVC. I have 2 files, test.swift and alphabetItemController.swift. The storyboard has, in addition to the landing page ViewController, a PageViewController called alphabetPVC, a ViewController called alphabetVC and a ViewController called TestVC.
Here is the code for alphabetItemController.swift ...
import UIKit
class alphabetItemController: UIViewController {
#IBOutlet weak var contentImageView2: UIImageView!
#IBOutlet weak var contentWordPn: UILabel!
var itemIndex: Int = 0
var imageName: String = ""
var wordPN: String = ""
var tTime: Timer!
override func viewDidLoad() {
super.viewDidLoad()
contentImageView2!.image = UIImage(named: imageName)
contentWordPn!.text = wordPN
}
}
Here is the code for test.swift ...
import Foundation
import UIKit
class testItemController: UIViewController, UIPageViewControllerDataSource {
var tTime: Timer!
override func viewDidLoad() {
super.viewDidLoad()
createPageViewController()
setupPageControl()
tTime = Timer.scheduledTimer(timeInterval: 5, target: self, selector: #selector(changeSlide), userInfo: nil, repeats: true)
//tTime = Timer.scheduledTimer(timeInterval: 5, target: self, selector: #selector(goToNextPage), userInfo: nil, repeats: true)
}
func changeSlide() {
pageViewController.setViewControllers(varPageVC, direction: UIPageViewControllerNavigationDirection.forward, animated: true, completion: nil)
}
// MARK: - Variables
private var varPageVC: UIPageViewController?
private let contentTextWordPN = ["A", "B", "C", "D", "E"]
private let contentCount = 5 //TODO ADJUST THIS FOR EACH COLLECTION
private func createPageViewController() {
let pageController = self.storyboard!.instantiateViewController(withIdentifier: "alphabetPVC") as! UIPageViewController
pageController.dataSource = self
if contentCount > 0 {
let firstController = getItemController(itemIndex: 0)!
let startingViewControllers = [firstController]
pageController.setViewControllers(startingViewControllers, direction: UIPageViewControllerNavigationDirection.forward, animated: false, completion: nil)
}
varPageVC = pageController
addChildViewController(varPageVC!)
self.view.addSubview(varPageVC!.view)
varPageVC!.didMove(toParentViewController: self)
}
private func setupPageControl() {
let appearance = UIPageControl.appearance()
appearance.pageIndicatorTintColor = UIColor.gray
appearance.currentPageIndicatorTintColor = UIColor.white
appearance.backgroundColor = UIColor.darkGray
}
func pageViewController(_ varPageVC: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
let itemController = viewController as! alphabetItemController
if itemController.itemIndex > 0 {
return getItemController(itemIndex: itemController.itemIndex-1)
}
return nil
}
func pageViewController(_ varPageVC: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
let itemController = viewController as! alphabetItemController
if itemController.itemIndex+1 < contentCount {
return getItemController(itemIndex: itemController.itemIndex+1)
}
return nil
}
private func getItemController(itemIndex: Int) -> alphabetItemController? {
if itemIndex < contentCount {
let pageItemController = self.storyboard!.instantiateViewController(withIdentifier: "alphabetVC") as! alphabetItemController
pageItemController.itemIndex = itemIndex
pageItemController.imageName = "alphabet_" + String(format: "%02d", (itemIndex + 1)) //alphabet_01
pageItemController.wordPN = contentTextWordPN[itemIndex]
return pageItemController
}
return nil
}
func presentationCountForPageViewController(varPageVC: UIPageViewController) -> Int {
return contentCount
}
func presentationIndexForPageViewController(varPageVC: UIPageViewController) -> Int {
return 0
}
func currentControllerIndex() -> Int {
let pageItemController = self.currentController()
if let controller = pageItemController as? alphabetItemController {
return controller.itemIndex
}
return -1
}
func currentController() -> UIViewController? {
if (self.varPageVC?.viewControllers?.count)! > 0 {
return self.varPageVC?.viewControllers![0]
}
return nil
}
}
extension UIPageViewController {
func goToNextPage(animated: Bool = true) {
guard let currentViewController = self.viewControllers?.first else { return }
guard let nextViewController = dataSource?.pageViewController(self, viewControllerAfter: currentViewController) else { return }
setViewControllers([nextViewController], direction: .forward, animated: animated, completion: nil)
}
func goToPreviousPage(animated: Bool = true) {
guard let currentViewController = self.viewControllers?.first else { return }
guard let previousViewController = dataSource?.pageViewController(self, viewControllerBefore: currentViewController) else { return }
setViewControllers([previousViewController], direction: .reverse, animated: animated, completion: nil)
}
}
There is even an extension UIPageViewController, but I do not know how to call the goToNextPage function.
I ended up changing the changeSlide() function... I had the next slide function in the extension already, and only the syntax to call it was eluding me... I found some examples on SO and used them as references:
func changeSlide() {
varPageVC?.goToNextPage()
}

DJI drone not connecting (sdkManagerProductDidChange delegate method not called)

I can't seem to get my own app to connect to a particular drone. I have downloaded the bridger app and am using it to debug. I copied the "DJIBaseViewController" from the sample app and have made my own view controller a delegate of it. After adding alot of breakpoints to the code I have found that the major difference between my app and the sample app is that the delegate method "sdkManagerProductDidChange."
// DJIBaseViewController.swift
import UIKit
import DJISDK
protocol DJIProductObjectProtocol {
func fetchAircraft() -> DJIAircraft?
func fetchCamera() -> DJICamera?
func fetchGimbal() -> DJIGimbal?
func fetchFlightController() -> DJIFlightController?
func fetchRemoteController() -> DJIRemoteController?
func fetchBattery() -> DJIBattery?
func fetchAirLink() -> DJIAirLink?
func fetchHandheldController() -> DJIHandheldController?
}
class ConnectedProductManager: DJIProductObjectProtocol {
static let sharedInstance = ConnectedProductManager()
var connectedProduct:DJIBaseProduct? = nil
func fetchAircraft() -> DJIAircraft? {
if (self.connectedProduct == nil) {
return nil
}
if (self.connectedProduct is DJIAircraft) {
return (self.connectedProduct as! DJIAircraft)
}
return nil
}
func fetchCamera() -> DJICamera? {
if (self.connectedProduct == nil) {
return nil
}
if (self.connectedProduct is DJIAircraft) {
return (self.connectedProduct as! DJIAircraft).camera
}
else if (self.connectedProduct is DJIHandheld) {
return (self.connectedProduct as! DJIHandheld).camera
}
return nil
}
func fetchGimbal() -> DJIGimbal? {
if (self.connectedProduct == nil) {
return nil
}
if (self.connectedProduct is DJIAircraft) {
return (self.connectedProduct as! DJIAircraft).gimbal
}
else if (self.connectedProduct is DJIHandheld) {
return (self.connectedProduct as! DJIHandheld).gimbal
}
return nil
}
func fetchFlightController() -> DJIFlightController? {
if (self.connectedProduct == nil) {
return nil
}
if (self.connectedProduct is DJIAircraft) {
return (self.connectedProduct as! DJIAircraft).flightController
}
return nil
}
func fetchRemoteController() -> DJIRemoteController? {
if (self.connectedProduct == nil) {
return nil
}
if (self.connectedProduct is DJIAircraft) {
return (self.connectedProduct as! DJIAircraft).remoteController
}
return nil
}
func fetchBattery() -> DJIBattery? {
if (self.connectedProduct == nil) {
return nil
}
if (self.connectedProduct is DJIAircraft) {
return (self.connectedProduct as! DJIAircraft).battery
}
else if (self.connectedProduct is DJIHandheld) {
return (self.connectedProduct as! DJIHandheld).battery
}
return nil
}
func fetchAirLink() -> DJIAirLink? {
if (self.connectedProduct == nil) {
return nil
}
if (self.connectedProduct is DJIAircraft) {
return (self.connectedProduct as! DJIAircraft).airLink
}
else if (self.connectedProduct is DJIHandheld) {
return (self.connectedProduct as! DJIHandheld).airLink
}
return nil
}
func fetchHandheldController() -> DJIHandheldController? {
if (self.connectedProduct == nil) {
return nil
}
if (self.connectedProduct is DJIHandheld) {
return (self.connectedProduct as! DJIHandheld).handheldController
}
return nil
}
func setDelegate(delegate:DJIBaseProductDelegate?) {
self.connectedProduct?.delegate = delegate
}
}
class DJIBaseViewController: UIViewController, DJIBaseProductDelegate, DJIProductObjectProtocol {
//var connectedProduct:DJIBaseProduct?=nil
var moduleTitle:String?=nil
override func viewDidLoad() {
super.viewDidLoad()
if (moduleTitle != nil) {
self.title = moduleTitle
}
// Do any additional setup after loading the view.
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
if (ConnectedProductManager.sharedInstance.connectedProduct != nil) {
ConnectedProductManager.sharedInstance.setDelegate(self)
}
}
override func viewWillDisappear(
animated: Bool) {
super.viewWillDisappear(animated)
if (ConnectedProductManager.sharedInstance.connectedProduct != nil &&
ConnectedProductManager.sharedInstance.connectedProduct?.delegate === self) {
ConnectedProductManager.sharedInstance.setDelegate(nil)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func product(product: DJIBaseProduct, connectivityChanged isConnected: Bool) {
if isConnected {
NSLog("\(product.model) connected. ")
ConnectedProductManager.sharedInstance.connectedProduct = product
ConnectedProductManager.sharedInstance.setDelegate(self)
}
else {
NSLog("Product disconnected. ")
ConnectedProductManager.sharedInstance.connectedProduct = nil
}
}
func componentWithKey(withKey key: String, changedFrom oldComponent: DJIBaseComponent?, to newComponent: DJIBaseComponent?) {
// (newComponent as? DJICamera)?.delegate = self
if ((newComponent is DJICamera) == true && (self is DJICameraDelegate) == true) {
(newComponent as! DJICamera).delegate = self as? DJICameraDelegate
}
if ((newComponent is DJICamera) == true && (self is DJIPlaybackDelegate) == true) {
(newComponent as! DJICamera).playbackManager?.delegate = self as? DJIPlaybackDelegate
}
if ((newComponent is DJIFlightController) == true && (self is DJIFlightControllerDelegate) == true) {
(newComponent as! DJIFlightController).delegate = self as? DJIFlightControllerDelegate
}
if ((newComponent is DJIBattery) == true && (self is DJIBatteryDelegate) == true) {
(newComponent as! DJIBattery).delegate = self as? DJIBatteryDelegate
}
if ((newComponent is DJIGimbal) == true && (self is DJIGimbalDelegate) == true) {
(newComponent as! DJIGimbal).delegate = self as? DJIGimbalDelegate
}
if ((newComponent is DJIRemoteController) == true && (self is DJIRemoteControllerDelegate) == true) {
(newComponent as! DJIRemoteController).delegate = self as? DJIRemoteControllerDelegate
}
}
func showAlertResult(info:String) {
// create the alert
var message:String? = info
if info.hasSuffix(":nil") {
message = info.stringByReplacingOccurrencesOfString(":nil", withString: " success")
}
let alert = UIAlertController(title: "Message", message: "\(message ?? "")", preferredStyle: .Alert)
// add an action (button)
alert.addAction(UIAlertAction(title: "OK", style: .Default, handler: nil))
// show the alert
self.presentViewController(alert, animated: true, completion: nil)
}
func fetchAircraft() -> DJIAircraft?{
return ConnectedProductManager.sharedInstance.fetchAircraft()
}
func fetchCamera() -> DJICamera? {
return ConnectedProductManager.sharedInstance.fetchCamera()
}
func fetchGimbal() -> DJIGimbal? {
return ConnectedProductManager.sharedInstance.fetchGimbal()
}
func fetchFlightController() -> DJIFlightController? {
return ConnectedProductManager.sharedInstance.fetchFlightController()
}
func fetchRemoteController() -> DJIRemoteController? {
return ConnectedProductManager.sharedInstance.fetchRemoteController()
}
func fetchBattery() -> DJIBattery? {
return ConnectedProductManager.sharedInstance.fetchBattery()
}
func fetchAirLink() -> DJIAirLink? {
return ConnectedProductManager.sharedInstance.fetchAirLink()
}
func fetchHandheldController() -> DJIHandheldController?{
return ConnectedProductManager.sharedInstance.fetchHandheldController()
}
}
The first view that loads after the splashscreen loads is.
// MenuViewController.swift
import UIKit
import DJISDK
let enterDebugMode=true
class MenuViewController: DJIBaseViewController {
#IBOutlet weak var aircraft: UILabel!
#IBOutlet weak var productID: UILabel!
// Do any additional setup after loading the view.
#IBOutlet weak var appConectivity: UILabel!
var connectedProduct:DJIBaseProduct?=nil
var componentDictionary = Dictionary<String, Array<DJIBaseComponent>>()
let APP_KEY = "*******"//Please enter App Key Here
override func viewDidLoad() {
super.viewDidLoad()
let air = self.fetchAircraft()
if air == nil{
aircraft.text?="no aircraft connected"
}
print(air?.model)
initUI();
guard !APP_KEY.isEmpty else {
showAlert("Please enter your app key.")
return
}
DJISDKManager.registerApp(APP_KEY, withDelegate: self)
if DJISDKManager.product() == nil{
productID.text?="Drone Not Connected"
}
else{
productID.text? = "Drone Connected"
}
}
func initUI() {
self.title = "DJI iOS SDK Sample"
//sdkVersionLabel.text = "DJI SDK Version: \(DJISDKManager.getSDKVersion())"
//openComponents.isEnabled = false;
//bluetoothConnectorButton.isEnabled = true;
//productModel.isHidden = true
//productFirmwarePackageVersion.isHidden = true
//debugModeLabel.isHidden = !enterDebugMode
}
func showAlert(msg: String?) {
// create the alert
let alert = UIAlertController(title: "", message: msg, preferredStyle: .Alert)
// add the actions (buttons)
alert.addAction(UIAlertAction(title: "OK", style: .Default, handler: nil))
// show the alert
self.presentViewController(alert, animated: true, completion: nil)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
extension MenuViewController: DJISDKManagerDelegate{
func sdkManagerDidRegisterAppWithError(error: NSError?) {
guard error == nil else {
self.showAlertResult("Error:\(error!.localizedDescription)")
appConectivity.text?="app isn't registering properly"
return
}
//Debug("Registered!")
if enterDebugMode {
DJISDKManager.enterDebugModeWithDebugId("10.202.38.238")
print("WTF")
}else{
//DJISDKManager.enterDebugModeWithDebugId("10.202.38.238")
DJISDKManager.startConnectionToProduct()
}
}
func sdkManagerProductDidChange(From oldProduct: DJIBaseProduct?, To newProduct: DJIBaseProduct?) {
print("entered changed product")
if oldProduct==nil{
print("old product is nill")
}
if newProduct==nil{
print("new product is nill")
}
guard let newProduct = newProduct else
{
appConectivity.text? = "Status: No Product Connected"
ConnectedProductManager.sharedInstance.connectedProduct = nil
//logDebug("Product Disconnected")
return
}
//Updates the product's model
productID.text = "Model: \((newProduct.model)!)"
productID.hidden = false
if let oldProduct = oldProduct {
print("Product changed from: \(oldProduct.model) to \((newProduct.model)!)")
}
//Updates the product's firmware version - COMING SOON
//Updates the product's connection status
//appConectivity.text = "Status: Product Connected"
ConnectedProductManager.sharedInstance.connectedProduct = newProduct
productID.text?="product connected"
//openComponents.isEnabled = true;
//openComponents.alpha = 1.0;
//logDebug("Product Connected")
}
override func product(product: DJIBaseProduct, connectivityChanged isConnected: Bool) {
if isConnected {
print("Status: Product Connected")
//appConectivity.text?="Drone Recognized"
} else {
print("Status: No Product Connected")
//appConectivity.text="Atleast Its trying"
}
}
}
The sdkManager is registering properly with the given app key and bundler identifier. I have also added "Supported external accessory protocols" to my info.plist file with three elements com.dji.video, com.dji.protocol, and com.dji.common.
Been stuck here for quite some time and it's been damn frustrating. Hope someone call help.
Thanks in advance.
I figured it out. The issue here is that the sample app has named its delegate
func sdkManagerProductDidChange(from oldProduct: DJIBaseProduct?, to newProduct: DJIBaseProduct?)
whereas for whatever reason in my sample app the DJISDK knows my delegates function as
func sdkManagerProductDidChangeFrom(oldProduct: DJIBaseProduct?, to newProduct: DJIBaseProduct?)
a bit annoying that that made such a big difference but that's what I get for copying code I guess. Hope this is helpful to someone else down the road...
Cheers
P.S. they may change it again the way I found it is when I typed func into my extension section Xcode spit out a list of functions I could use and the sdkManagerDidChange was one of them with different input variables.
edit: if anyone can explain why it worked on the sample app and not mine that would be sweet too.

Apple CareKit symptom code in swift doesn't save data to CareStore

The following code was working partially. It display the question step and form. User was able to enter data, but when user click done nothing get save to care store and the display is not updated. Any idea?
class SymptomsVC1: UIViewController{
fileprivate let carePlanStoreManager = CarePlanStoreManager1.sharedCarePlanStoreManager
fileprivate let carePlanData: CarePlanData
fileprivate var symptomTrackerViewController: OCKSymptomTrackerViewController? = nil
required init?(coder aDecoder: NSCoder) {
carePlanData = CarePlanData(carePlanStore: carePlanStoreManager.store)
super.init(coder: aDecoder)
}
override func viewDidLoad() {
super.viewDidLoad()
setViewControllerTitle(self, title: "Symptoms Card")
//creatMenuObject(self)
let symptomTracker = OCKSymptomTrackerViewController.init(carePlanStore: carePlanStoreManager.store)
symptomTracker.progressRingTintColor = UIColor.magenta
symptomTracker.delegate = self
symptomTracker.showEdgeIndicators = true
// Setup the controller's title
symptomTracker.title = NSLocalizedString("Symptoms Card", comment: "")
//change left navigation "Back" button to menu button
var backImage:UIImage = UIImage(named: "menu")!
backImage = backImage.withRenderingMode(UIImageRenderingMode.alwaysOriginal)
let fakeBackButton = UIBarButtonItem(image: backImage, style: UIBarButtonItemStyle.bordered, target: symptomTracker.revealViewController(), action: #selector(SWRevealViewController.revealToggle(_:)))
symptomTracker.navigationItem.leftBarButtonItem = fakeBackButton;
self.navigationController?.pushViewController(symptomTracker, animated: true)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
extension SymptomsVC1: OCKSymptomTrackerViewControllerDelegate {
func symptomTrackerViewController(_ viewController: OCKSymptomTrackerViewController, didSelectRowWithAssessmentEvent assessmentEvent: OCKCarePlanEvent) {
if viewController.progressRingTintColor == UIColor.magenta {
guard let userInfo = assessmentEvent.activity.userInfo,
let task: ORKTask = userInfo["ORKTask"] as? ORKTask else { return }
let taskViewController = ORKTaskViewController(task: task, taskRun: nil)
taskViewController.delegate = self
present(taskViewController, animated: true, completion: nil)
}
}
}
extension SymptomsVC1: ORKTaskViewControllerDelegate {
func taskViewController(_ taskViewController: ORKTaskViewController, didFinishWith
reason: ORKTaskViewControllerFinishReason, error: Error?) {
defer {
dismiss(animated: true, completion: nil)
}
print("task view controller clicked")
guard reason == .completed else { return }
guard let symptomTrackerViewController = symptomTrackerViewController,
let event = symptomTrackerViewController.lastSelectedAssessmentEvent else { return }
let carePlanResult = carePlanStoreManager.buildCarePlanResultFrom(taskResult: taskViewController.result)
print("care plan result")
print(carePlanResult)
carePlanStoreManager.store.update(event, with: carePlanResult, state: .completed) {
success, _, error in
if !success {
print(error?.localizedDescription)
}
}
}
}
I found the fix by adding one line of code in the following function :
override func viewDidLoad() {
super.viewDidLoad()
setViewControllerTitle(self, title: "Symptoms Card")
//creatMenuObject(self)
let symptomTracker = OCKSymptomTrackerViewController.init(carePlanStore: carePlanStoreManager.store)
symptomTracker.progressRingTintColor = UIColor.magenta
symptomTracker.delegate = self
symptomTracker.showEdgeIndicators = true
// Setup the controller's title
symptomTracker.title = NSLocalizedString("Symptoms Card", comment: "")
//*** add the following line, now the result show up in carestore ***
symptomTrackerViewController = symptomTracker
//change left navigation "Back" button to menu button
var backImage:UIImage = UIImage(named: "menu")!
backImage = backImage.withRenderingMode(UIImageRenderingMode.alwaysOriginal)
let fakeBackButton = UIBarButtonItem(image: backImage, style: UIBarButtonItemStyle.bordered, target: symptomTracker.revealViewController(), action: #selector(SWRevealViewController.revealToggle(_:)))
symptomTracker.navigationItem.leftBarButtonItem = fakeBackButton;
self.navigationController?.pushViewController(symptomTracker, animated: true)
}

Resources