Compatibility issue with Xcode generated swiftinterface file - swift

I'm working with a Cocoa Touch framework, built for distribution, which uses Core Data managed object subclasses. When I implement the framework in a client project built with the same Xcode/Swift version as the framework, the app compiles successfully.
However, when I build the framework with Xcode 11.1 (Swift 5.1), and implement the framework in a client project using Xcode 11.2.1 (Swift 5.1.2), I get a compile error in the property declaration of the generated "swiftinterface" file. "#NSManaged not allowed on computed properties"
From Framework project NSManagedObject subclass:
extension TestEntity {
#nonobjc public class func fetchRequest() -> NSFetchRequest<TestEntity> {
return NSFetchRequest<TestEntity>(entityName: "TestEntity")
}
#NSManaged public var id: Int64
}
From Framework .swiftinterface file:
#objc #NSManaged dynamic public var id: Swift.Int64 {
#objc get
#objc set(value)
}
If I remove the setter-getter, the client app builds and runs, but I see this warning:
Cannot load Swift type information; AST validation error in "my_test_framework": The module file format is too old to be used by this version of the debugger.
Thoughts, rants, lessons, and/or workarounds are welcome!

Related

swift codegen file error

Working with coredate I used the option codegen: category/extension to be able to create a file where I can put in the re-usable code for finding, updating or deleting database entries.
I started the coredata entity first with the codegen option Class Definition and changed it to category/extension in a later stage.
Now I run against a compile error:
'Property cannot be declared public because its type uses an internal type'
The file name is a generated swift file called:
Gameresults+Coredataproperties.swift
I got the error on the player: TournamentPlayer?
player and round are both relations to another entity.
import Foundation
import CoreData
extension GameResults {
#nonobjc public class func fetchRequest() -> NSFetchRequest<GameResults> {
return NSFetchRequest<GameResults>(entityName: "GameResults")
}
#NSManaged public var earnedRankingPoints: Int16
#NSManaged public var framePoints: Int16
#NSManaged public var highestBreak: Int16
#NSManaged public var isWon: Bool
#NSManaged public var player: TournamentPlayer?
#NSManaged public var round: Rounds?
}
I could not believe that the error did come out of swift so I tried the clean build folder option, saving file, exiting XCode, etc. Nothing worked.
Any tips where to look at how to fix this?
Use the Manual/None option for the codegen.
There are a couple of things that you should consider here.
when you use codegen it automatically creates all classes which are equivalent to your entities as public. I assume TournamentPlayer class is not public and you have definded it yourself. so based on default definition it is internal and the compiler gives you the error correctly. the only thing you can do here is changing the access level and because you're using the codegen and it means you want to change your model, so it's better to change your TournamentPlayer to public. Although it depends on the architecture of your application.
The codegen is automatically regenrated whenever you change your model and is saved in DerivedData.
If you want to take care of it yourself you set it to manual and you handle the code generation yourself manually.
check this article, it gives you a better understanding of codegen https://useyourloaf.com/blog/core-data-code-generation/
one more thing, when you change to manual/none you have to do a clean build otherwise it still uses the generated code in DerivedData

Framework entry point in Swift

I just started playing with frameworks in xcode trying to create my own module. When making an iOS app its relatively straightforward where the entry point is ( AppDelegate )
However the framework I've created has nothing like a "main.swift" or similar method.
Do i have to create/specify the entry point on my own?
Thanks
EDIT: The reason i'd like the framework to be runnable is so that i can actually print some output while I'm making it to make sure everything works properly.
(My TL;DR is at the bottom.)
As already stated, there is no entry point like you are thinking. Instead, you should do this:
In your Framework target (I'll assume the framework is named MyFramework):
Add files, classes, properties, subclassed controls, etc. and mark things as public, private, internal, and fileprivate. (See the access level section in the Apple documentation.)
For instance:
public class MyClass1 {
public var property1 = ""
private var property2 = ""
public func myFunc() -> String {
print("Hello World!")
}
}
private class MyClass2 {
var property1 = ""
var property2 = ""
func myFunc() -> String {
return "Hello World!"
}
}
In your app target (again, assuming your framework is named myFramework):
include MyFramework
class ViewController: UIViewController {
func tryThis() {
let myClass1 = myClass1()
print(myClass1.myFunc()) // prints "Hello World!"
// the line below will generate a build error
// as myClass2 is marks private
let myClass2 = myClass2()
}
}
TL;DR
Learn your Access Levels, add code into your Framework target, and import the framework into your app.
A framework doesn't have a traditional entry point like this - it won't ever be run by itself, so it doesn't need one.
To use your framework you would create an app which linked with your framework - the entry point for the app would then call methods from inside your framework.
An answer I got from #deanWombourne points out that if anyone wants to only use the framework project for development as is and develop the framework without integrating it in an app for execution, they can just use the tests provided by the framework for an entry point.
For someone that might be new, all you need to is include unit tests to your project, press on the play button which you normally press on for running and select the wrench icon that writes "test" next to it to run the tests.

Errors after 'Create NSManagedObject Subclass for CoreData Entities

I have created 2 core data entities and then created NSManagedObject Subclasses for them from the editor menu.
However when I run my app I get errors on every line of all the files for some reason.
Here is an example, these errors are the same for both entities created files.
File Code was auto generated so i can apste it here but not sure of its use
import Foundation
import CoreData
extension UserExercise {
#nonobjc public class func fetchRequest() -> NSFetchRequest<UserExercise> {
return NSFetchRequest<UserExercise>(entityName: "UserExercise");
}
#NSManaged public var id: Int16
#NSManaged public var name: String?
#NSManaged public var reps: Int16
#NSManaged public var sets: Int16
#NSManaged public var weight: Int16
#NSManaged public var relationship: NSSet?
}
// MARK: Generated accessors for relationship
extension UserExercise {
#objc(addRelationshipObject:)
#NSManaged public func addToRelationship(_ value: UserRoutine)
#objc(removeRelationshipObject:)
#NSManaged public func removeFromRelationship(_ value: UserRoutine)
#objc(addRelationship:)
#NSManaged public func addToRelationship(_ values: NSSet)
#objc(removeRelationship:)
#NSManaged public func removeFromRelationship(_ values: NSSet)
}
Errors are:
Command/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftc failed with exit code 1
Invalid redeclaration of 'UserRoutine'
'UserExercise' is ambiguous for type lookup in this context
#NSManaged only allowed on an instance property or method
Theres too many to list its basically these repeated over and over
Xcode by default manage generation of these subclasses for you. If you want to manage generation of them yourself then:
Select your entities in the data model.
Find Codegen in the utilities pane(right pane) and set it to Manual/None.
Clean and build.
The current default in Xcode is to automatically create subclasses of NSManagedObject for you in the /Users/<your user name>/Library/Developer/Xcode/DerivedData/AppName-agkwmibzbo‌​pevjgfajlcbyixzyev/B‌​uild/Intermediates/A‌​ppName.build/Debug-i‌​phonesimulator/AppNa‌​me.build/DerivedSour‌​ces/CoreDataGenerate‌​d/Modeldirectory; The DerivedData directory is where Xcode saves automatically generated code. You are redeclaring the same subclass by doing Editor>Create NSManagedObject Subclass... that is why you are getting the "Invalid redeclaration of 'UserRoutine' 'UserExercise' is ambiguous for type lookup in this context #NSManaged only allowed on an instance property or method" error. To resolve the errors and manually create a subclass of NSManagedObjects what you need to do is:
Open terminal and navigate to /Users/<your user name>/Library/Developer/Xcode/DerivedData/AppName-agkwmibzbo‌​pevjgfajlcbyixzyev/B‌​uild/Intermediates/A‌​ppName.build/Debug-i‌​phonesimulator/AppNa‌​me.build/DerivedSour‌​ces/CoreDataGenerate‌​d/Model
Run this command: rm -rf * (now be careful with this command, run it only when you get to the final directory where the generated codes are or you'll break your project for good)
Delete your current data model
Create a new data model
Select your new data model's entity (do this for each entity within the data model) and go to its attributes inspector and set its Codegen to Manual/None Before the first run after you have created a new data model.
Create a subclass of NSManagedObject by going to Editor>Create NSManagedObject Subclass...
Your errors should disappear.
Hope this helped!
A simple approach that worked for me .... You can find these by choosing an entity and clicking on the Data Model Inspector at the top right . Do this for all of your entities
Its important to FIRST set Module to "Current Product Module" AND Codegen to "Manual/None"
Only then, SECOND: Editor -> Create NSManagedObject subclass.
This is for Swift 3.0 and Xcode 8.2.1(8C1002)
Not sure why you would manually navigate to the project when you can just instead delete the files directly from Xcode.
Find all of your generated files from the xcdatamodeld, inside of your project navigator. Delete all of the files and make sure you move to trash, do not remove references otherwise you're going to have to manually delete the files from:
/Users//Library/Developer/Xcode/DerivedData/AppName-agkwmibzbo‌​pevjgfajlcbyixzyev/B‌​uild/Intermediates/A‌​ppName.build/Debug-i‌​phonesimulator/AppNa‌​me.build/DerivedSour‌​ces/CoreDataGenerate‌​d/Model
Ok so after you've deleted the files, open your xcdatamodeld, select all of your entities, and in the Utilities panel, select Data Model Inspector button, and make sure that Codegen is set to "Manual/None".
Select your xcdatamodeld and make sure that that Codegen is set to "Manual/None"
Keep all of your entities selected and click Editor > Create NSManagedObject Subclass, make sure to select the folder and drag and drop your generated files in your Model sub-group and your Generated sub-group.
This worked for me and it should work for you too.
I hope that I have helped you.
I also ran into this bug. I fixed it by deleting the old generated entity subclasses and creating it again and for the group I selected the workspace instead of the project or folder in the project, and the subclasses got saved above the project file. It looks weird but it fixed the issue. Also if i move the files into the folder inside the project the error reappears.
I ran into this issue during unit testing due to recreating my NSPersistentContainer over and over again in every unit test. It looks like loading the same managed object model repeatedly could lead to this.
My resolution was to use a single shared instance across all of my unit tests and do clean up between them accordingly.
I was getting the "... is ambiguous for type lookup in this context" error when building a simple SwiftUI Mac app for testing this issue after running Editor/Create NSManagedObject subclass..." with Xcode Version 13.4 (13F17a) on macOS Monterey 12.3.1.
I found a solution in deselecting/unchecking the checkbox for "Targets" in the final dialog before clicking "Create". This checkbox was selected by default. Clearing it and clicking "Create" resulted in a successful build.
This results with the subclass files at the top level of the project structure:

Singleton problems with Swift 2.2

After updating to XCode 7.3 and Swift 2.2, everything with my iOS project seemed fine and I have no compile errors or warnings. It worked perfectly when compiling to Swift 2.1
However, after the update, as soon as the app launches, it freezes and XCode returns an EXC_BAD_ACCESS error, with no messages on the console. The problem is with my 'sharedInstance' singleton, for some reason it won't work.
The code goes as follows:
class Authenticator {
private init() {}
static let sharedInstance = Authenticator()
private let parseDAO = ParseDataAccessObject.sharedInstance
var place: Place?
var placeObj: PFObject?
var menu: Menu?
var consumables: [Consumable]?
var tables: [Table]?
....
}
When the app launches, it returns the following error:
Debug
Error
Are one of the types of those properties an enum with a single case? There is a bug with the newest version of Swift that causes a EXC_BAD_ACCESS error when an object is initialized with a single-case enum property that is not optional. Here is the relevant Swift bug tracker issue: https://bugs.swift.org/browse/SR-1035
For a temporary fix, add another case to the enum.

Create and import swift framework

I'm new in swift programming.
I need to create pure swift framework and import it in my existing pure swift project.
When I try to import swift framework, I'm getting this error
message:
"Could not build Objective-C module '<myModule>'"
Test.h
import Foundation
public class Test {
class func printTest() {
println("111");
}
}
Asdf.h
import UIKit
public class Asdf: Test {
class func echo() {
println(888);
}
}
myModule-Swift.h
#ifndef <myModule>_<myModule>_Swift_h
#define <myModule>_<myModule>_Swift_h
#endif
After framework build, i have added framework in my existing project and get this
What am I doing wrong? Thanks For Help!
#findall comment answer -
I tried to add all framework files to my project root folder and inside project folder, but again got the same error
I've done with the following steps.
Create a framework project, for example named "FooKit". (Cocoa Touch Framework to be selected)
Create a ".swift" file and add a public symbol, for example public func foo(), to it.
Create an use-side (app) project. (I've chosen Single View Application)
Open the root directory of "FooKit" by Finder, drag "FooKit.xcodeproj" there and drop it into the app project via Project Navigator.
Add "FooKit" to Target Dependencies in the app's Build Phases setting.
Add "FooKit.framework" to Embedded Binaries in the app's General setting.
Now you can build like this code in the use-side app.
import FooKit
func bar() {
foo()
}
In Xcode 7.2 using Swift 2.1 I managed to get past the mentioned error by making sure that the build settings of your pure Swift framework called Foo are as follows:
1) Build Settings->Packaging->Defines Module = Yes
2) Build Settings->Swift Compiler - Code Generation->Install Objective-C Compatibility Header = Yes (if you do not need to import your Swift framework into Objective C set this setting to No)
3) Erase the string value of Build Settings->Swift Compiler - Code Generation->Objective-C Bridging Header
4)Build Settings->Swift Compiler - Code Generation->Objective-C Generated Interface Header Name = Foo-Swift.h (if you do not need to import your Swift framework into Objective C erase this setting as you did in step 3))
5) Make sure that Build Settings->Packaging->Product Name = Foo
6) Add to the public umbrella header of your framework (Foo.h), which you can use to import your Swift code to Objective C, the following line:
#import "Foo-Swift.h"
(but if you do not need to import your Swift code into objective C skip this step)
6) Add the following line to the Swift file where you want to use the module Foo:
import Foo
Important notes:
1) Ensure that your umbrella header Foo.h is set to public in the File Inspector, otherwise this won't work.
2) If you are using your pure Swift framework in Objective C files, ensure that:
the Foo-Swift.h header has generated the correct interface by going to Foo.h and then clicking on the top left corner menu of the Xcode code editor and then choosing Includes->Foo-Swift.h (I had to rebuild the Foo framework a few times until Xcode caught-up with the change and then generated the correct interface in Objective C, so you may need to do that as well)
your swift classes inherit from NSObject or they won't be available to Objective C code
Additionally for #jvarela's answer, in Xcode 9 and swift 4,
To import Swift framework in an Objective C project, you must add
#objc
mark to all of your classes, methods and variables which you want to export into Objective C project .
For example,
#objc public class Foo: NSObject {
#objc public var fooDescription: String
#objc public func foo(){
}
}
On Swift:
Create Framework:-
Start Xcode -> Create a new Xcode Project -> iOS -> Framework & Library -> Cocoa Touch Framework -> Name the framework(ex. sampleCocoaFramework) -> Create.
Set Taget -> General -> Deployment info -> Deployment Target.
Add a public class: File -> New File -> iOS -> Swift File -> Name it (ex. openCocoaClass) -> Create.
Now add some code to the openCocoaClass.swift.
import Foundation
public class openCocoaClass {
public init() {
}
public var samplePublicVariable = "samplePublicVariable # openCocoaClass"
public func samplePublicFunction()
{
print("samplePublicFunction # openCocoaClass")
}
}
Clean the project : Product -> Clean
Configure the scheme settings : Product -> Scheme -> Edit Scheme -> Run -> Build Configuration -> Release.
Build the framework : Product -> Build.
Export the framework : Products -> Select the framework -> Identity and type -> Full Path -> Released Framework.
Adding Framework to Project:-
Start a Xcode project and name it (ex. CocoaFrameworkTest).
Drag and drop the sampleCocoaFramework.framework to the CocoaFrameworkTest's project folder.
Target -> General -> Embed Binaries -> Add Other -> Select Framework
-> Copy Items if needed -> Done.
Accessing Framework on ViewController:-
import UIKit
import sampleCocoaFramework
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let frameworkObject = openCocoaClass.init()
frameworkObject.samplePublicFunction()
print(frameworkObject.samplePublicVariable)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}