XCGLogger: Ambiguous reference to member 'log' - swift

Trying to set up XCGLogger and receiving error:
Ambiguous reference to member 'log'
I see this issue was already raised but I'm not clear on the solution..
Per the install guide added this global constant to AppDelegate.swift:
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
let log = XCGLogger.defaultInstance()
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
log.setup(.Debug, showThreadName: true, showLogLevel: true, showFileNames: true, showLineNumbers: true, writeToFile: nil, fileLogLevel: .Debug)
return true
}
Then in individual source files:
import XCGLogger
log.debug("A debug message")
What is the proper usage?

The issue is rather simple. If you declare log inside AppDelegate, you are making an instance variable. To access it, you will have to access it as instance variable:
(UIApplication.sharedApplication().delegate as! AppDelegate).log.debug("test")
If you want log to be accessible everywhere, you will have to make it a global constant:
In your AppDelegate, declare a global constant to the default XCGLogger instance.
let log = XCGLogger.defaultInstance()
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
(there is no need to declare it in AppDelegate file, you can basically put it anywhere in your code)
or make it static:
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
static let log = XCGLogger()
and access it using:
AppDelegate.log.debug(...)
To explain the ambigious reference, there is a mathematical function called log, and there is also a log function in the malloc.h file. Since you are passing a String as the first parameter and neither of the two functions is a match, the compiler warns you that it does not know which of the two functions you want to use.

Also I guess it's better to create global constant file and create something like this (if you've declared log in AppDelegate):
let LOG = (UIApplication.sharedApplication().delegate as! AppDelegate).log
and then simple use LOG.error("error")

Related

Error with appDelegate while testing firebase based app

Im trying to do some snapshot tests on my firebase based app.
I made some snapshot tests with 'LogInVC' it worked well because it has nothing in common with firebase but then, after LoginTests I've tried to test tableView that should be shown after successful login:
First I made "TestingAppDelegate" in test target:
import UIKit
#objc(TestingAppDelegate)
class TestingAppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
print(">> Launching with testing app delegate")
return true
}
To avoid the regular app delegate during testing I made a code in a file called "main" that tries to find a class named TestingAppDelegate made in "Testing" target and also deleted #main in regular AppDelegate.
import UIKit
let appDelegateClass: AnyClass =
NSClassFromString("TestingAppDelegate") ?? AppDelegate.self
UIApplicationMain(CommandLine.argc, CommandLine.unsafeArgv, nil,
NSStringFromClass(appDelegateClass))
This is how my test looks:
class UsersTests: XCTestCase {
var sut: AllUsersViewController!
override func setUp() {
sut = AllUsersViewController()
sut.loadViewIfNeeded()
}
override func tearDown() {
sut = nil
}
func testInitialLoginScreen(){
setUsers()
assertSnapshot(matching: sut, as: .image, record: true)
}
func setUsers(){
for number in 0...5{
let user = UserInfo(firstName: "Nikola", lastName: "Andr", username: "lol", pictureURL: nil, training: ["lol","mma"], uid: "\(number)", admin: false)
sut.users.append(user)
}
}
When I run tests this is error I get in "main" file that switches app delegates.
"The default FirebaseApp instance must be configured before the
default Authinstance can be initialized. One way to ensure this is to
call FirebaseApp.configure() in the App Delegate's
application(_:didFinishLaunchingWithOptions:) (or the #main
struct's initializer in SwiftUI)."
I've never tested firebase app before so I don't know that to do now. Any reference where to learn about how to test firebase apps will be helpful too.

How do you use Firebase within a custom class?

I went through the steps to set up Firebase on my app and it tested well. But when I created a custom swift class to make functions to manage the database, it crashes and says "failed to get default firdatabase instance. must call firapp.configure() before using firdatabase". I called configure() in the AppDelegate but it doesn't seem to be passing through to my custom class. Below is the error I get, my part of the AppDelegate where i called FirebaseApp.configure(), and the custom class. Thanks in advance.
DatabaseTestApp[7814:336288] *** Terminating app due to uncaught exception 'FIRAppNotConfigured', reason: 'Failed to get default FIRDatabase instance. Must call FIRApp.configure() before using FIRDatabase.'
import UIKit
import Firebase
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
FirebaseApp.configure()
return true
}
}
my custom class:
import Foundation
import UIKit
import FirebaseDatabase
class FirebaseClass
{
var ref:DatabaseReference?
init ()
{
ref = Database.database().reference()
}
}
Assuming you are creating some sort of class called FirebaseManager, do the following:
class FirebaseManager {
public static let instance = FirebaseManager()
private init(){
FirebaseApp.configure()
}
}

Access a viewController struct from appDelegate

I have a struct defined in my ViewController as follows:
struct Meme {
var topText : String
var bottomText : String
var originalImage : UIImage
var memedImage: UIImage
}
Now when I try to access the struct from appDelegate using the following code, I get an unresolved identifier error:
var memes = [Meme]()
can someone please explain why this is happening and how can i access the viewController struct from my appDelegate?
Thanks!
You can't access the properties of a class without having an instance of it.
In AppDeletegate file do this:
// create instance of your viewcontroller class
let viewController = ViewController()
// access the property
viewController.memes = [Meme]()
This is possible in another way to:
import UIKit
var memes = [Meme]()
class ViewController: UIViewController {
}
ok the memes are not exacly in the scope of UIViewController, but they are in the same file, like this they are global variable.
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
print(memes[0].bottomText)
return true
}
Wish you all the best.
Assuming the struct is defined inside your ViewController class like you said, you will need to access it using the namespace of the ViewController in the following way:
var memes = [MyViewController.Meme]()
I actually figured this out long back. Sorry for the delay in update. People with the same problem, please create a new swift file called "Meme.swift" and then write the meme struct inside that file. Your problem should be solved now. Thanks!

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!

May I create an instance of AppDelegate?

I'm using Appdelegate with some timers to do background checks. How can I trigger to do a check right now.
I would have something like this in my Appdelegate:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
NSTimer.scheduledTimerWithTimeInterval(10.0, target: self, selector: "test", userInfo: nil, repeats: true)
return true
}
func test() -> Bool {
print("true")
return true
}
is it admissable to do something like the following from any other class inside the app?
AppDelegate().test()
If you need access to some method or property of your app delegate, you could do something like this:
if let appDelegate = UIApplication.sharedApplication().delegate as? AppDelegate {
// Use your app delegate instance:
appDelegate.test()
}
Also, the code you wrote:
AppDelegate.test()
...is wrong; here test() is an instance method, so it should be called on an instance (not the class - notice the capital initial).
You can, but not by making another instance of AppDelegate but use the shared instance of it.
if let delegate = UIApplication.sharedApplication().delegate as? YOURAPPDELEGATE
Try above code.
In model unit tests it's often nice not to have UIApplication like framework classes, as they interfere with your tests in unforeseeable ways. But it's no problem at all to instantiate as many instances of your UIApplicationDelegate as you want:
let sut = AppDelegate()
XCTAssertTrue(sut.test(), "test failed")
It's a delegate class and as such, does not interfere with UIKit by just instantiating.
Also in normal app code you could do the same without harming the rest of your app—it's just less common to do these kind of tests within the actual app target.