In swift, extension NSManagedObjectContext can not be in a separate file? - ios

In Xcode, when I create a new file extends NSManagedObjectContext class, add methods in this extension file, compile the project and there is no problem.
NSManagedObjectContext+BaseModel.swift
import Foundation
import CoreData
import CoreDataStack
extension NSManagedObjectContext {
public func insertObject<T: NSManagedObject>() -> T {
guard let object = NSEntityDescription.insertNewObjectForEntityForName(T.modelName(), inManagedObjectContext: self) as? T
else {
fatalError("Invalid Core Data Model")
}
return object
}
}
However, when I use it in the ViewController.swift, like context.insertObject(), the compiler reports an error saying:
Value of type 'NSManagedObjectContext' has no member 'insertObject'
After searching in StackOverflow, I found a post "Using extensions in separate .swift file". As the post author said, the above problem disappeared when I put the extension NSManagedObjectContext code in my custom CoreDataStack.swift. But why?? Should not extension Apple's class be in a separate file??

Related

How to prevent importing specific framework on Xcode

Lets say I created swift frameworks on Xcode like below
Wireframe
Entity
I kept all frameworks "Frameworks and Libraries" section on Xcode empty.
However I'm still able to access both from Wireframe -> Entity and Entity -> Wireframe.
// A class belongs to Wireframe
import Entity // <- This does not raise error
public class MyRouter: NSObject {
public func hoge() {
let board = Book()
}
}
// A class belongs to Entity
import Wireframe // <- This does not raise error
public class Book: NSObject {
public var name: String = ""
public override init() {
super.init()
let router = Wireframe.MyRouter()
}
}
Is it possible to prevent importing specific framework to another framework(like showing compile error if tried by writing "import ") that I can assure architecture is not messed up.
Xcode automatically links to frameworks that Swift imports, as described here. But you can disable this with the “Link Frameworks Automatically” build setting.

Type conversion SIGABRT

I'm trying to load classes from a framework dynamically but the application crashes with conversion sending SIGABRT signal:
let newClassType = NSClassFromString("MyFramework.CustomClass") as! BaseClass.Type
With classes declared in MyApp it works fine as well as with framework's classes but without conversion.
BaseClass.swift (MyApp.xcodeproj and copied to MyFramework):
public class BaseClass{
...
}
CustomClass.swift(MyFramework.xcodeproj):
public class CustomClass: BaseClass{
...
}
What might be the problem?
From The question and the comments I suggest to use typealias
import MyFramework
typealias FrameworkBaseClass = MyFramework.BaseClass
typealias FrameworkCustomClass = MyFramework.CustomClass
Then if you want to use FrameworkBaseClass, FrameworkCustomClass in other .swift files, you do not have to import MyFramework

Swift2.0 CoreData issue on NSFetchRequest

This is a code snippet of me trying to fetch data from coredata. I tried to fetch data and checked using breakpoint and there was NO data fethed! The code is in swift2. Any suggestions would be appreciated. I defined a struct constants where I defined all the constants. gate is a string type defined in nsmanagedobject class. The snippet is a part of viewDidLoad() method.
let context: NSManagedObjectContext? = (UIApplication.sharedApplication().delegate as? AppDelegate)?.managedObjectContext!
let TPTodayFetchRequest = NSFetchRequest(entityName: Constants.CoreDataEntities.TPTodayCoreDataEntity)
do {
let patroDaily = try context!.executeFetchRequest(TPTodayFetchRequest) as! [TPToday]
for patroEntity in patroDaily {
print(patroEntity.gate)
}
}
catch { print("error") }
Except for cumbersome variable naming, and unfortunate indentation, your code is fine and should work.
You will have to investigate if you have indeed saved the data you are expecting to find. For example, you could have the program log the documents directory URL after which you could examine the sqlite file with the sqlite3 command line tool.

App doesn't enter in the initial ViewController using Typhoon

I have created a project to test the Typhoon framework , I have created two classes ApplicationAssembly and CoreAssembly where I inject some properties and constructors and a default Configuration.plist to load data from it.
ApplicationAssembly
public class ApplicationAssembly: TyphoonAssembly {
public dynamic func config() -> AnyObject {
return TyphoonDefinition.configDefinitionWithName("Config.plist")
}
}
CoreAssembly
public class CoreAssembly: TyphoonAssembly {
public dynamic func apiHandler() -> AnyObject {
return TyphoonDefinition.withClass(ApiHandler.self) {
(definition) in
definition.useInitializer("initWithDebugging:debugProcess:mainURL:") {
(initializer) in
initializer.injectParameterWith(TyphoonConfig("debug_mode"))
initializer.injectParameterWith(TyphoonConfig("debug_path"))
initializer.injectParameterWith(TyphoonConfig("api_url"))
}
definition.scope = TyphoonScope.Singleton
}
}
public dynamic func viewController() -> AnyObject {
return TyphoonDefinition.withClass(ViewController.self) {
(definition) in
definition.injectProperty("apiHandler", with:self.apiHandler())
}
}
}
I set in my Info.plist the TyphoonInitialAssemblies first the ApplicationAssembly and then the CoreAssembly.
Everything works fine without exceptions or anything except that the app never enters in AppDelegate neither in the ViewController class. I don't know maybe I missed something in the doc or anything.
What I'm missing here?
Why in debug not enter in the ViewController class that is the initial view controller in Storyboard?
The problem was that the ApiHandler class does not extend NSObject, which is a requirement. This is because Typhoon is an introspective Dependency Injection container. As Swift has no native introspection it uses the Objective-C run-time.
The App should not however have crashed in such an obfuscated way. I have opened an issue to look at how to fail with a meaningful error, rather than infinitely recurse.
After solving the initial problem, I also noted that the init method for ApiHandler passing in a Swift Bool object. This needs to be an NSNumber.
init(debugging : NSNumber, debugProcess : String, mainURL : String) {
self.debugging = debugging.boolValue
self.debugProcess = debugProcess
self.mainURL = mainURL
}
Given that Typhoon uses the Objective-C runtime, there are a few quirks to using it with Swift - the same kinds of rules outlined for using Swift with KVO apply.

Make a Data Class with Swift in Watchkit Target

As simply using the sharedApplication() method is unavailable in WatchKit, utilizing the AppDelegate as a way to store data for all my interfaces/views is no longer an option in WatchKit. Is there an alternative method to do this in swift for WatchKit apps? I have tried making a singleton class like so:
import Foundation
import UIKit
class data: NSObject {
class var sharedInstance : data {
struct Example {
static let instance = data()
}
return Example.instance
}
var value:Int = 0
var increment:Int = 1
}
(This code is from another StackOverflow post, I just forgot the link.) I then try and access the Integer "value" by calling data.value in an interface controller but I get the error 'data.Type' does not have a member named 'value'. How can I fix this error? Or is there a better way to do what I am trying to achieve?
Thanks
The code data.value attempts to access a class variable or method on the class data called value. Since no such variable or method exists you get the error message.
In your definition value is defined as a property on the class data, so to use it you need a valid instance of data. Your sharedInstance method provides the instance.
Also, the convention in Swift is to capitalize class names, so I recommend using Data.

Resources