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.
Related
I have a weird crash that I managed to reproduce in skeleton app.
I have a framework which uses RxSwift az a cocoapod dependency.
It has a simple class defined:
public final class FWSupplier {
public let psubject = PublishSubject<Int>()
public let bsubject = BehaviorSubject<Int>(value: 0)
public init() { }
public func triggerBehaviour() {
self.bsubject.onNext(1)
}
public func triggerPublish() {
self.psubject.onNext(1)
}
}
I build the framework as an XCFramework and import it into a host app.
In the app I simply instantiate the FWSupplier in a view controller and call triggerPublish and it crashes.
class ViewController: UIViewController {
#IBOutlet var label: UILabel!
let supplier = FWSupplier()
override func viewDidLoad() {
super.viewDidLoad()
supplier.triggerPublish()
}
}
Anyone have any idea what I'm doing wrong?
Screenshot of error
Screenshot of stack
Do not mix release and debug. When you build XCFramework, it depends on the release version rxswift. When you build the host app, it uses the debug version rxswift. There is some #if Debug in the rxswift source code,mixing release and debug may cause a crash. Instead, you should build the release version rxswift framework and add it to the podspec.vendored_frameworks.
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
In Core data when I create a data model, I choose to generate the category extension, I understand that this is created in derived data
I want to be able to view this in the XCode code editor but I don't know how I can open it just to view it.
I am using XCode 9 beta 3
The ways I can manage to do this is by typing some thing such as
let m = MenuItem()
let n = m.name
In the code editor and then command clicking on name and then it jumps to the file, or finding the generated extension in Finder and opening from there.
//
// MenuItem+CoreDataProperties.swift
//
//
// Created by Ryan.Heitner on 01/08/2017.
//
// This file was automatically generated and should not be edited.
//
import Foundation
import CoreData
extension MenuItem {
#nonobjc public class func fetchRequest() -> NSFetchRequest<MenuItem> {
return NSFetchRequest<MenuItem>(entityName: "MenuItem")
}
#NSManaged public var available: Bool
#NSManaged public var desc: String?
#NSManaged public var name: String?
#NSManaged public var price: Double
}
The category extension seems buggy to me. Just select "Manual/None", then select an entity or all entities and click on Editor->Create NSManagedObject Subclass, choose your entities and the extensions should be shown under your project root in Xcode.
Unfortunately what you're doing is the only option Xcode provides. It's not good, but you haven't missed anything. I suggest filing a bug with Apple about this. In the meantime, either deal with this as it is, or switch to some other means of generating your properties-- manually maybe, or using mogenerator.
I have the following set of files in my project:
The IAPHelper class uses the objective-c through a bridging header. I was wondering if I could use the IAPHelper class in both my app and its app extension like this:
(Setting IAPHelper's target membership)
Without making KeychainWrapper being a member of both classes.
No it does not seem to work.
I made TestClassOne
import Foundation
class TestClassOne {
static internal func addOneOne() -> Int {
return 2;
}
}
TestClassOne is only part of one target.
I made TestClassTwo
import Foundation
class TestClassTwo {
internal static func callTestClassOne() -> Int {
let i = TestClassOne.addOneOne()
return i
}
}
TestClassTwo belonged too both targets. I would keep on getting the error TestClassOne not recognized when the TestClassOne file was set to only one target but once I set the TestClassOne file to both targets that error stopped appearing.
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.