Exception on API Key of Google Maps API for iOS - ios

I am developing an iOS app using Google Maps API for IOS. And I installed the CocoaPod for my project and configure them according to tutorial on Google Developer. However, when I run my project, it says
*** Terminating app due to uncaught exception 'GMSServicesException', reason: 'Google Maps SDK for iOS must > be initialized via [GMSServices provideAPIKey:...] prior to use'
But I already call "GMSServices.provideAPIKey on the AppDelegate.swift. Following is the code:
....
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
GMSServices.provideAPIKey("***********************")
return true
}
....
(**************) is my API Key.
And because Google Maps API use Objective C, so I created a Bridging Header to import the library.
I tried to set breakpoint on [application:didFinishLaunchingWithOption]. But it will raise exception before run that function, which I think is very weird.
So confused about it. Thanks in advance.

Problem finally solved, the reason is that I initialize a fields using Google Maps library in the one model class and it will be created before the app run. So this error happens. When I moved this variable into the method, problem solved. Following is the code that causes error:
class PlaceManager {
let placeClient = GMSPlacesClient()
...
func getSuggestions(queryString:String) -> [String]{
...
}
}
After
class PlaceManager {
func getSuggestions(queryString:String) -> [String]{
let placeClient = GMSPlacesClient()
...
}
}

Instead of didFinishLaunchingWithOptions, move the call to willFinishLaunchingWithOptions. This method is called after state restoration has occurred but before your app’s window and other UI have been presented. (Which in your case might be a UI that consumes Google Map API)
func application(application: UIApplication, willFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
GMSServices.provideAPIKey("***********************")
return true
}

I just had the same problem. I created a GMSMapView object and it was initialized before maybe the api key could be read. So I moved it inside the viewDidLoad method and problem solved.
Before :
class ViewController: ..... {
let mapView = GMSMapView()
After :
class ViewController: ..... {
var mapView : GMSMapView?
override viewDidLoad(){
mapView = GMSMapView()

Related

Chartboost Delegate not working in swift

Desired : I want to do something when Delegates method call Observed :Delegates method not calling Ad's show on the screen successfully
Error
code:Chartboost.delegate=self
Error: Type 'Chartboost' has no member 'delegate'
AppDelegate
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
Chartboost.start(withAppId: "4f21c409cd1cb2fb7000001b", appSignature: "92e2de2fd7070327bdeb54c15a5295309c6fcd2d", delegate: nil)
return true
}
ViewController Code
class ViewController: UIViewController,GADBannerViewDelegate, GADInterstitialDelegate,GADRewardBasedVideoAdDelegate,IMBannerDelegate, IMInterstitialDelegate ,ChartboostDelegate{
#IBAction func Vedio(_ sender: Any) {
Chartboost.showRewardedVideo(CBLocationMainMenu)
}
#IBAction func LoadFullAd(_ sender: Any) {
Chartboost.showInterstitial(CBLocationHomeScreen)
}
private func shouldDisplayRewardedVideo(_ location: CBLocation) -> Bool {
return true
}
private func shouldRequestInterstitial(_ location: CBLocation) -> Bool {
return true
}
}
A had to set the delegate as self with Chartboost.setDelegate(self)
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
Chartboost.start(withAppId: "4f21c409cd1cb2fb7000001b", appSignature: "92e2de2fd7070327bdeb54c15a5295309c6fcd2d", delegate:self as ChartboostDelegate)
Chartboost.setDelegate(self as ChartboostDelegate)
return true
}
After looking at how to properly convert Objective-C methods in Swift, I added the underscore (_), which changed the function to:
func shouldDisplayRewardedVideo(_ location: CBLocation) -> Bool
{
return true
}
func shouldRequestInterstitial(_ location: CBLocation) -> Bool {
return true
}
XCode then gave me a hint that I was close to the delegate method, but needed to change the type of location and I ended up with
func shouldDisplayRewardedVideo(_ location: String) -> Bool
{
return true
}
func shouldRequestInterstitial(_ location: String) -> Bool {
return true
}
If the delegate is set to nil, the class that calls the delegate's methods (in this case Chartboost) will not be able to make the delegate's method calls. You should set the delegate to the 'self' of the class where you have implemented the delegate methods expected by Chartboost.
In the example above, you could set the Chartboost delegate to the 'self' of the ViewController.
For example, inside of ViewController, you have already declared the 'ChartboostDelegate' in the class signature. When you want to turn on the Chartboost delegate methods, assign the ViewController's 'self' to the Chartboost delegate using something like:
Chartboost.delegate = self
In the case of Chartboost, it looks like the author made the delegate private, so it can be set in the ViewController using:
Chartboost.start(withAppId: "some uid", appSignature: "some other uid", delegate: self)
or, as later found out:
Chartboost.setDelegate(self)
(It can also be set in the AppDelegate class by locating the ViewController instance in the storyboard. Not a great fit in this case.)
If you're having problems generating the delegate method's call signature stubs (the method calls expected by the delegate), XCode will autogenerate them for you. Just click on the error message found next to your class declaration:
Type '<your class implementing the delegate methods>' does not conform to protocol '<the delegate protocol to implement>'
More detail about the error will appear. Click the 'Fix' button and XCode will autogenerate the method stubs for you.

Firebase observer during all the app life

I'm trying to create a firebase observer that remains alive during all the app life. What I want is to change a property of my tabBarController when some data change in firebase. Here's my code:
self.ref.child("mySubRef").observe(.value , with: {snapshot in
self.tabBarController?.tabBar.items?[3].badgeValue = "!"
})
So, I've tried creating it in the viewDidLoad of my first viewController and also in the viewDidAppear. I don't remove it since I want it to be there always. In the viewDidAppear it works only if I'm in that viewController at the moment of the change. If I want that change to happen no matter where I am (always inside the tabBar) where do I have to put that code?
Thanks for the help!
I have found the answer. The problem was that when I changed between viewControllers the reference to the observer was deallocated. So, to fix it, I have created a class like this:
class NotificationListener: NSObject {
let ref:FIRDatabaseReference = FIRDatabase.database().reference()
var user:User?
func setUpListener(tabBarController:UITabBarController){
self.user = User()
self.ref.child("users/" + self.user!.uid + "/notifications").observe(.value , with: {snapshot in
tabBarController.tabBar.items?[3].badgeValue = "!"
})
}
}
Now I have a property of that class in every viewController and every one has a reference to the same object. When I change between VC it will not deallocate the object because it will still be referenced.
I think, you can use Appdelegate didFinishLaunchingWithOptions method but I'm not sure.
Like this:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
FIRApp.configure()
FIRDatabase.database().reference().child("mySubRef").observe(.value, with: { (snapshot) in
//I'm not sure for this part.
UITabBarController.init().tabBar.items?[3].badgeValue = "!"
})
return true
}

Typhoon Dependency Injection and Swift 3: Appdelegate isn't AnyObject

This code works with Typhoon Dependency Injection library (Obj-C) in Swift 2.3 but doesn't in Swift 3:
AppDelegate:
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var rootViewController: RootViewController?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window?.rootViewController = self.rootViewController
self.window?.makeKeyAndVisible()
return true
}
...
}
Application Assembly:
public class ApplicationAssembly: TyphoonAssembly {
public dynamic func config() -> AnyObject {
return TyphoonDefinition.withConfigName("Configuration.plist")
}
public dynamic func appDelegate() -> AnyObject {
return TyphoonDefinition.withClass(AppDelegate.self) {
(definition) in
definition!.injectProperty(#selector(ApplicationAssembly.rootViewController), with: self.rootViewController())
}
}
...
}
However the following error is displayed in ApplicationAssembly for any Swift 3 file expected to return 'AnyObject':
"No 'withClass' candidates produce the expected contextual result type 'AnyObject'
Might anyone have an insight into the incompatibility of the Obj-c Typhoon code base with Swift 3?
Screen capture of error line
You may want to switch the return type from AnyObject to Any.
The withClass function returns an id type in Objective-C, see the source code:
+ (id)withClass:(Class)clazz block:(TyphoonBlockDefinitionInitializerBlock)block;
The id type used to be mapped to AnyObject in Swift 2, but in Swift 3 it's mapped to Any for increased flexibility. You can read more about this change here.

Swift Code in App Delegate to Load Storyboard Causes Crash

I have an universal app I am writing and I initially wrote it using two storyboard files. I had code in the App Delegate didFinishLaunchingWithOptions routine to decide which storyboard to load and away it would go. I have since realised that that was a silly thing to do because I had duplicate code, so I have deleted one storyboard and made the other universal. I have fixed up the VCs to point at the right class and everything. However, my app now refuses to launch. When I run it in the sim, it gives me the error
The app delegate must implement the window property if it wants to use a main storyboard file.
.
Here is my code in App Delegate:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
var deviceIdiom = UIDevice.currentDevice().userInterfaceIdiom
if deviceIdiom == UIUserInterfaceIdiom.Phone {
strDevice = "iPhone"
} else if deviceIdiom == UIUserInterfaceIdiom.Pad {
strDevice = "iPad"
} else {
strDevice = "Unknown"
}
return true
}
What am I doing wrong?
(Questions I've already looked at but didn't help):
Unique Issue displaying first storyboard scene in Xcode
The app delegate must implement the window property if it wants to use a main storyboard file
Managing two storyboards in App Delegate
How to manually set which storyboard view to show in app delegate
Swift - Load storyboard programatically
Your app delegate needs to start like such:
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
//...
}

openURL in APPDelegate conversion error NSString -> String (Swift & iOS8)

I'm currently developing an iOS application that integrates Facebook and I'm having a bit of a problem while investigating this with Swift (with ObjC I have no problems).
The thing is, this is the method that gets executed in the appDelegate when coming from another APP (in this case FB in a WebBrowser):
func application(
application: UIApplication,
openURL url: NSURL,
sourceApplication: NSString,
annotation: AnyObject)
-> Bool {
let appString : String = sourceApplication as String // Try to convert format => EXCEPTION
let appString : String = String(sourceApplication) // 'SSS' Suggestion: EXCEPTION
println(sourceApplication) // Try to print the value => EXCEPTION
return FBAppCall.handleOpenURL(url, sourceApplication:sourceApplication,
withSession:session) // With Parse => EXCEPTION
}
And inside that method I'm having real trouble with the 'sourceApplication' parameter. I try to use it, I get an exception. I try to convert it, another exception...can't even log its value because it crashes when accessing its value. Changing the parameter type in the functions signature to String neither worked.
This is the error I'm getting:
EXEC_BAD_ACCESS
And I've been able to track down until I could read this that it's definitely a valuable hint:
ObjectiveC.NSString.__conversion (ObjectiveC.NSString)() -> Swift.String
Could it be an iOS8 bug?
Any of you has had this problem and/or knows how to solve it?
You have made two mistakes:
The function declaration from the app Delegate is func application(application: UIApplication!, openURL url: NSURL!, sourceApplication: String!, annotation: AnyObject!) -> Bool : sourceApplication is an optional String value not NSString.
Since sourceApplication is an optional it may return nil value (In your case returning nil) . Type casting nil to String is not safe , therefore it is crashing.
Solutions :
No type casting is required in your case Since returned value is String type
Use optional form type cast operator as? to safely type cast i.e
if let appString = sourceApplication {
println(appString as? String)
}
This is working for me (with FacebookSDK):
func application(application: UIApplication, openURL url: NSURL, sourceApplication: NSString?, annotation: AnyObject) -> Bool {
var wasHandled:Bool = FBAppCall.handleOpenURL(url, sourceApplication: sourceApplication)
return wasHandled
}
I don't get this in the playground. Could be a iOS 8 bug as you suggest
But for the sake of trying, can you try
let appString : String = String(sourceApplication)
For FB Messenger here's what I did to get some better handling in my AppDelegate. Most of the ideas were taken straight from the FB IOS documentation and ported to Swift.
Why did I feel like I should write an additional reply? I've got some experience with Swift, but felt like I wasted enough time trying to get the right set of code to do what I wanted with FB Messenger. Hopefully the raw code is useful to someone, just to consolidate a lot of bits and pieces and save some time.
NOTE: This does not include all the AppDelegate lifecycle methods you'll want/need, but hopefully it's a head start
#UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate, FBSDKMessengerURLHandlerDelegate {
var window: UIWindow?
var messengerUrlHandler: FBSDKMessengerURLHandler?
var cancelContext : FBSDKMessengerURLHandlerCancelContext?
var composerContext : FBSDKMessengerURLHandlerOpenFromComposerContext?
var replyContext: FBSDKMessengerURLHandlerReplyContext?
// Facebook Messenger
enum MessengerShareMode : Int {
case MessengerShareModeCancel
case MessengerShareModeSend
case MessengerShareModeComposer
case MessengerShareModeReply
}
// shareMode holds state indicating which flow the user is in.
// Return the corresponding FBSDKMessengerContext based on that state.
var shareMode : MessengerShareMode?
/*
* Initialize the FB messenger handler and set self as the delegate.
*/
func application(application: UIApplication, willFinishLaunchingWithOptions launchOptions: [NSObject : AnyObject]?) -> Bool {
YARAppearance.setAppearance()
let rootController = TabBarController()
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
self.window!.rootViewController = rootController
self.window!.makeKeyAndVisible()
// Facebook messenger handling
self.messengerUrlHandler = FBSDKMessengerURLHandler()
if (self.messengerUrlHandler != nil) {
self.messengerUrlHandler!.delegate = self
}
return true
}
/*
* Handle the cancel context flow.
*/
func messengerURLHandler(messengerURLHandler: FBSDKMessengerURLHandler!,
didHandleCancelWithContext context: FBSDKMessengerURLHandlerCancelContext!) {
self.cancelContext = context
self.shareMode = .MessengerShareModeCancel
}
/*
* When people enter your app through the composer in Messenger,
* this delegate function will be called.
*/
func messengerURLHandler(messengerURLHandler: FBSDKMessengerURLHandler!,
didHandleOpenFromComposerWithContext context: FBSDKMessengerURLHandlerOpenFromComposerContext!) {
self.composerContext = context
self.shareMode = .MessengerShareModeComposer
}
/*
* When people enter your app through the "Reply" button on content
* this delegate function will be called.
*/
func messengerURLHandler(messengerURLHandler: FBSDKMessengerURLHandler!,
didHandleReplyWithContext context: FBSDKMessengerURLHandlerReplyContext!) {
self.replyContext = context
self.shareMode = .MessengerShareModeReply
}
/*
* Handle URL calls from external applications, particularly Messenger
*/
func application(application: UIApplication, openURL url: NSURL, sourceApplication: String?, annotation: AnyObject) -> Bool {
let wasHandled:Bool = self.messengerUrlHandler!.openURL(url, sourceApplication: sourceApplication)
return wasHandled
}
/*
* A way to access the context objects elsewhere
*/
func getContextForShareMode() -> FBSDKMessengerContext? {
// shareMode holds state indicating which flow the user is in.
// Return the corresponding FBSDKMessengerContext based on that state.
if (shareMode == .MessengerShareModeSend) {
// Force a send flow by returning a broadcast context.
return FBSDKMessengerBroadcastContext()
} else if (shareMode == .MessengerShareModeComposer) {
// Force the composer flow by returning the composer context.
return self.composerContext!
} else if (shareMode == .MessengerShareModeReply) {
// Force the reply flow by returning the reply context.
return self.replyContext!
}
return nil
}
}

Resources