Accessing sub assembly of an assembly will generate EXC_BAD_ACCESS - ios

Use case:
I have an ApplicationAssembly. This assembly has a property called CoreAssembly of type TyphoonAssembly. I'm using PLIST integration and have registered both Assemblies. I'm injecting the ApplicationAssembly into the Appdelegate.
Afterwads in a ViewController, I want to get an object which will be generated by CoreAssembly
var appdelegate = UIApplication.sharedApplication().delegate as! AppDelegate;
tagHandler = appdelegate.assembly.coreAssembly.tagHandler() as! GoogleTagsHandler;
If I do this, I get an EXC_BAD_ACCESS

This seems to be a bug, we've logged it. In the meantime, as a workaround, please inject both ApplicationAssembly and CoreAssembly into your app delegate as follows:
public dynamic func appDelegate() -> AnyObject {
return TyphoonDefinition.withClass(AppDelegate.self) {
(definition) in
definition.injectProperty("assembly", with: self)
definition.injectProperty("coreAssembly", with: self)
}
}

Related

Swift: avoid to force unwrap constant variable

I'm trying to avoid a force unwrap of global variables. How can I do that in this particular example:
let AppDelegate = UIApplication.shared.delegate as! AppDelegate
If you don't want to force-unwrap (which is fine here in this case), then use if let.
if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
// Do something with appDelegate
}
But the force-unwrap is fine for this. You want the app to crash during development if you make a typo on the type of the app delegate. It will never fail at runtime unless you make a change to the code and ship it to Apple without at least running your app once.
Made this an extension so no copy paste anymore. This is as type safe as it gets since it only makes sense for the AppDelegate to implement UIApplicationDelegate and the one is always reachable via UIApplication.shared.delegate.
#if os(macOS)
import Cocoa
typealias ApplicationDelegate = NSApplicationDelegate
typealias Application = NSApplication
#else
import UIKit
typealias ApplicationDelegate = UIApplicationDelegate
typealias Application = UIApplication
#endif
public extension ApplicationDelegate {
static var shared: Self {
return Application.shared.delegate as! Self
}
}
If you want to use the variable locally then:
if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
//logic here
}
or
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {return}
I don't think there is a way to use AppDelegate globally without using force casting.
Edited
To create a global variable, just declare it anywhere outside a class. For example:
var globalVariable = 1
class Person {
//logic here
}

Swift: getting AppDelegate instance as a class func results in Thread 1: EXC_BAD_INSTRUCTION

I want to get my AppDelegate reference from a class func in my AppDelegate. Why is this throwing a Thread 1: EXC_BAD_INSTRUCTION?
class func getDelegate() -> AppDelegate {
return UIApplication.sharedApplication().delegate as! AppDelegate
}
I have also tried to move this to another utility class and as a regular func, but getting the same crash.
Is there a way I can access the AppDelegate as a class func instead of having to write
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
in every class?
Declare class function to get appDelegate in AppDelegate class as
class func getDelegate() -> AppDelegate {
return UIApplication.sharedApplication().delegate as! AppDelegate
}
To access and use appDelegate in other class, call
let delegate = AppDelegate.getDelegate()
delegate.printHello()
Create a class as shown below[in a new class file or in existing class file outside the previous class. No need to put it inside AppDelete.swift file]
class Delegate
{
static var appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
}
and you can use it as Delegate.appDelegate in any class.

How to use a variable in other class that is defined in AppDelegate

I have a variable var window: UIWindow? in AppDelegate.swift file inside class AppDelegate that I want to use in other class xyz.swift file inside class xyz as explained in here Get current view controller from the app delegate (modal is possible) but I am getting error at the first line any help will be appreciated. here is the code from xyz.swift
func CurrentView() -> UIView
{
let navigationController = window?.rootViewController as? UINavigationController // Use of Unresolved identifier 'window'
if let activeController = navigationController!.visibleViewController {
if activeController.isKindOfClass( MyViewController ) {
println("I have found my controller!")
}
}
}
Even if I use let navigationController = AppDelegate.window?.rootViewController as? UINavigationController error is 'AppDelegate.Type' does not have member named 'window'
You may have to do as follows:
var appDelegate = UIApplication.sharedApplication().delegate as AppDelegate
let navigationController = appDelegate.window?....
As #Dave Durbin has pointed out you are trying to use a variable defined in one class into another class without the reference of the defining class.
This line of code is in xyz.swift
let navigationController = window?.rootViewController as? UINavigationController // Use of Unresolved identifier 'window'
You don't provide any context for window so it's expected to be in this class or a global variable.
This is closer:
navigationController = AppDelegate.window?.rootViewController as? UINavigationController
and you seem to realise that you need to reference the window variable within your AppDelegate instance however the syntax you are using references a static variable and window is a member variable.
I suggest you read through the swift manual and gain a better understanding of variable scopes and check this:
How do I get a reference to the app delegate in Swift?

Use of undeclared type 'AppDelegate' Swift

I've just spent half a day trying to solve next problem.
I am testing the CoreData using Swift language.
Follow this tutorial everything works fine.
But after titorial I've tried to modify the structure and my code. The 'src' and groups inside it is folders, not just groups created by xCode.
NSSExpense.swift
import Foundation
import CoreData
class NSSExpense: NSManagedObject {
#NSManaged var name: String
#NSManaged var descr: String
#NSManaged var value: NSNumber
#NSManaged var isMonthly: NSNumber
#NSManaged var payDayInMonth: NSNumber
class func createInManagedObjectContext(moc: NSManagedObjectContext, name: String, value: Double, payDayInMonth: Int16, isMonthly: Bool, descr: String!) -> NSSExpense {
let newExpense = NSEntityDescription.insertNewObjectForEntityForName("NSSExpense", inManagedObjectContext: moc) as NSSExpense
newExpense.name = name
newExpense.value = NSNumber(double: value)
newExpense.payDayInMonth = NSNumber(short: payDayInMonth)
newExpense.isMonthly = NSNumber(bool: isMonthly)
if let expenseDesctiption = descr {
newExpense.descr = expenseDesctiption
} else {
newExpense.descr = ""
}
return newExpense
}
}
NSSDataManager.swift
import UIKit
import CoreData
class NSSDataManager: NSObject {
class var sharedDataManager: NSSDataManager {
struct Static {
static var instance: NSSDataManager?
static var token: dispatch_once_t = 0
}
dispatch_once(&Static.token) {
Static.instance = NSSDataManager()
}
return Static.instance!
}
lazy var managedObjectContext : NSManagedObjectContext? = {
// Error at the next line "Use of undeclared type 'NSSAppDelegate'"
let appDelegate = UIApplication.sharedApplication().delegate as NSSAppDelegate
if let managedObjectContext = appDelegate.managedObjectContext {
return managedObjectContext
} else {
return nil
}
}()
var expensesInMemory : [NSSExpense] {
get {
let fetchRequest = NSFetchRequest(entityName: "NSSExpense")
if let fetchResults = managedObjectContext!.executeFetchRequest(fetchRequest, error: nil) as? [NSSExpense] {
return fetchResults
} else {
return [NSSExpense]()
}
}
}
func addExpenseWithName(name: String, value: Double, payDayInMonth: Int16, isMonthly: Bool, descr: String!) -> NSSExpense {
return NSSExpense.createInManagedObjectContext(managedObjectContext!, name: name, value: value, payDayInMonth: payDayInMonth, isMonthly: isMonthly, descr: descr?)
}
}
I've tried to solve this problem different ways:
1) Create new project (Swift main language) and make the same structure again (failed)
2) Create new project (Objective-C main language). So I have the AppDelegate.h and AppDelegate.m. Add it to Swift files using Bridging-Header. The same problem. (failed)
Really interesting next thing. If I put next code to the ViewController.swift which creates automatically with new project everything works fine. But when I put this code to any other class. I've code this error.
lazy var managedObjectContext : NSManagedObjectContext? = {
// Error at the next line "Use of undeclared type 'NSSAppDelegate'"
let appDelegate = UIApplication.sharedApplication().delegate as NSSAppDelegate
if let managedObjectContext = appDelegate.managedObjectContext {
return managedObjectContext
} else {
return nil
}
}()
[UPDATE 1]
I've tried to create another class right at the same folder as NSSAppDelegate.swift and now everything works fine. However it's still an issue, how can I use the classes which stored in other folders?
[UPDATE 2]
Just tried to do the same thing in other project.
If the file structure is like this so the AppDelegate.swift and NGDataManager.swift are in the same folder everything works great.
BUT, if I put the NGDataManager.swift inside the 'src' folder like this (not just group, folder) the error occurs. May be I should create the other question for this.
[UPDATE 3]
I don't know how, but you can forget all I've said in UDATE 2. Because Now thats all not work. I even create a new project with CoreData named "Test" and just create a new class named "TestClass". The magic is in the next thing: if I put this code inside the TestClass.swift
import UIKit
class TestClass: NSObject {
func someFunc() {
let appDel = UIApplication.sharedApplication().delegate as AppDelegate
}
}
the error occurs. But if I put this line in viewDidLoad in ViewController.swift which was generated automatically by xCode
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let appDel = UIApplication.sharedApplication().delegate as AppDelegate
}
}
their is no error and everything works great. I don't know what to say...
You may see the AppDelegate code here but I didn't modify anything generated automatically by xCode. I've created a Single View Application with this settings.
Chances are when you created your project you also created a '{ProjectName}Tests' target. The problem is AppDelegate is not assigned membership in the '{ProjectName}Tests' target.
Select AppDelegate.swift then in the right-hand inspector click on the File Inspector (the paper icon) then make sure in the "Target Membership" both your project and the test target checkmarks are set to ON.
Clean, rebuild.
If trying to access an Objective-C AppDelegate in Swift code, make sure you have #import "AppDelegate.h" in your bridging header file.
This had me stuck for about an hour :-/
I had a similar problem that was resolved when I did a "Clean" option in the Product menu
Ran into this issue in Xcode 8 and this was the first result when I searched on google so adding my solution.
If your project has UI and Unit Tests, make sure your AppDelegate is added to both target memberships. Once I added it to my Tests I was able to access any variables I had in my AppDelegate without having to use UIApplication.shared regardless of how my files were grouped.
To check, go to your AppDelegate, click on the file inspector, and look at Target Membership.
Make sure the Target Memberships are set the same in each file. Target memberships can be found in the properties inspector when you click on a specific file.
It suppose to be like this.
let appDelegate: AppDelegate = (UIApplication.sharedApplication().delegate as! AppDelegate)
Instead of:
let appDelegate = UIApplication.sharedApplication().delegate as NSSAppDelegate
try:
let appDelegate = UIApplication.sharedApplication().delegate as AppDelegate

Swift Passing data from appDelegate to another class

I need to pass a variable from the AppDelegate to another class that I have created to hold global variables of the project and I'm not able to find a way to make it work.
This is the code in the AppDelegate:
func application(application: UIApplication!, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData!) {
println("Device's token is: \(deviceToken)")
//Global Variables Class Instance
let globals:Globals = Globals()
globals.setDeviceToken("test1") //method1 not working
globals.deviceToken = "test2" //method2 not working
}
This is my Globals Class:
public class Globals {
var deviceToken = String()
init() {
//nothing
}
func setDeviceToken(s:String){
deviceToken = s
}
func getDeviceToken() -> String {
return deviceToken
}
}
If i try to print the value, from other files of the project, I'm not able to get anything, just an empty string.
class ViewController: UIViewController {
//Global Variables Class Instance
let globals:Globals = Globals()
override func viewDidLoad() {
println(globals.getDeviceToken()) //return empty string
println(globals.deviceToken) //return empty string
There are several patterns you can use to achieve what you want
You could access the AppDelegate through the UIApplication:
let delegate = UIApplication.sharedApplication().delegate as AppDelegate
let deviceToken = delegate.deviceToken
Look into singletons. A quick google search for 'Swift singleton' will get you a long way. The first result:
class SingletonB {
class var sharedInstance : SingletonB {
struct Static {
static let instance : SingletonB = SingletonB()
}
return Static.instance
}
}
Then use sharedInstance to instantiate the singleton anywhere and access the same variables.
The first one is quick and dirty, so for more serious projects I would recommend the singleton pattern.
There are probably a million ways to do this, but this should get you started
(More at this link, which explores a few ways to implement singletons: https://github.com/hpique/SwiftSingleton )
I simply solved my problem using NSUserDefaults
in the AppDelegate:
NSUserDefaults.standardUserDefaults().setObject(deviceToken, forKey: "deviceToken")
NSUserDefaults.standardUserDefaults().synchronize()
From other classes:
NSUserDefaults.standardUserDefaults().objectForKey("deviceToken")
Honestly I don't know if this is a good way to do it but it's working

Resources