Importing classes from playground page into another page - swift

Note: This is a different question than importing generic swift files (which can be done using the Sources folder).
I have a playground with 2 pages and I would like to use a protocol defined in the first page in the second page. I'll use an example of JSON conversion.
JSON.xcplaygroundpage
import Foundation
protocol JSONConvertible {
func jsonValue() -> String
}
JSONArray.xcplaygroundpage
import Foundation
//Undeclared type JSONConvertible
extension Array : JSONConvertible {
}
I have tried the following imports:
import MyPlayground
import MyPlayground.JSON
import JSON
import JSON.Contents (in finder the file name is actually Contents.swift)
I have also tried adding JSON.xcplaygroundpage into the Source folder of JSONArray as well as the Resources folder.
Note: I realize that I could put the protocol definition in a separate JSON.swift and include that in my project Sources folder. That doesn't really answer my question.

This is working in Xcode 8.3.3.
For code common to multiple pages, put it in separate files under top-level Sources group. Be sure to have proper Swift access control keywords in the right places.
Note from http://help.apple.com/xcode/mac/8.2/#/devfa5bea3af:
...the auxiliary Swift source file must export it using the public keyword. This includes classes, methods, functions, variables, and protocols.
Common.swift:
public class DoIExist { public init(){ print("Woot!")} }
Then you can reference it in all of the other pages. Like this:
Page2:
//: [Previous](#previous)
let d = DoIExist()
//: [Next](#next)
You can see that it works because of the console output ("Woot!") and the view results gutter.
To achieve this, I followed the directions at the Apple Xcode documentation about Playgrounds. When Apple inevitably moves those docs and does not provide a forwarding link, read on for how I found it.
I searched for the clues found in the link in cocoapriest's answer: "ios recipes Playground Help Add Auxilliary Code to a Playground". This leads to a document Apple is currently calling "Xcode Help" in a chapter titled "Use playgrounds" in a section titled "Add auxiliary code to a playground".

Just got this to work with this instruction by Apple: https://developer.apple.com/library/ios/recipes/Playground_Help/Chapters/AddAuxilliaryCodetoaPlayground.html
Make sure to declare your classes are public. Also, I had to re-start the Xcode to take the effect.

Related

Swift public func not being exported from framework

I created a Swift Framework project in Xcode and I'm trying to export a function for Unity to call. I defined the function like this.
#_cdecl("showPaymentForm")
public func showPaymentSheet()-> PKPaymentAuthorizationViewController?{
NSLog("In showPaymentForm - Navtive code.")
return ApplePayLib.showPaymentSheet(label: "something", total: 9.99, mainViewController: nil)
I ran
nm -gU
against the binary and it doesn't show any functions exported called showPaymentForm. I check the "Symbols Hidden by Default" to make sure it was set to "No".
If I do the same as above in a package instead of a framework, it works fine. I didn't stick with the package project because I need to include other packages that didn't play nice with it.
Not really sure what else to check.
It turned out the issue was due to the swift file not having a target selected. Once I selected the correct target, the function as exported correctly.

Using Swift Code inside of a Nativescript Plugin

I'm new to Nativescript and Swift and I'm trying to use one of Nativescript's most useful feature. The Ability to use Swift/Objective C code directly inside of your Typescript code.
So in my plugin I have this swift File: /ios/src/TestClass.swift
open class TestClass {
#objc public func testTestClass() {
return "It Works!"
}
}
but when I try to generate type information for this class using ns typings ios, No types are generated for this class.
I've also tried annotating the class with #objc(TestClass) and still the same result.
I have some cocapod libraries for which types are being generated.
Is it possible in Nativescript to use Swift files directly? or have I misunderstood the documentation?.
Edit: Turning the package into a coca pod makes everything work.

Xcode Playgrounds: Source files are unable to be accessed by each other

I am creating a playground in Xcode and I do not understand why the "Sources" files cannot talk to each other. I am using SpriteKit which means it is ideal to have one swift file per scene, in my case I have one scene per level. I cannot use a quick workaround and add everything into one massive file... there has to be a better way. Both classes for the two swift files are public. You should be able to access them. Thanks!
I get this error when I try to an object from one class, LevelScene, in the other class TitleScene.
After this
let levelScene = LevelScene(fileNamed: "LevelScene")
This happens
Cannot find 'LevelScene' in scope
I am aware of this post. This solution still does not work for me.
Xcode playgrounds can't access swift files in Sources folder
I am on Xcode 12.4.
Thanks!
You need to declare all your classes/struct in each file as public.
So, if you have defined a struct like this in a file:
struct Node {
var id: Int
}
You need to declare is like so:
public struct Node {
var id: Int
}
Then your code should work. You can use a struct from one file in another file as long as you declare them as public. Similar concept goes for any functions/methods inside those structs/classes. Even with this solution, you may find Xcode 12.4 complaining about not finding the type in scope. That, I believe, is a known bug. I have the same bug on my Xcode 12.4. I am able to build and run the code even with that error.

Type extensions from a framework's dependency available in app

OK... this is difficult to explain (and to come up with a title for) but I'll try my best.
We first discovered this when using Carthage to import stuff but setting up a sample project in Xcode (without using Carthage) it seems to have done the same thing.
First, here's a screenshot of the sample project we set up...
The have a target Test20000 and it has a dependency A.
The A framework then has a dependency on B.
Important
The Test20000 app does NOT add B as a direct dependency.
The frameworks
In B there is a struct like...
import Foundation
public struct BType {
public let value = "Hello, B!"
}
In A there is a file like...
import Foundation
import B
public struct AType {
public let value = "Hello, A!"
public func doAThing() {
print(BType().value)
}
}
The App
Now in the Test20000 app we do something like...
import Foundation
import A
struct TestType {
func doSomething() {
let aType = AType()
print(aType.value)
aType.doAThing()
}
}
This works as expected. It prints...
Hello, A!
Hello, B!
If I change the function to something like this...
import Foundation
import A
struct TestType {
func doSomething() {
let bType = BType()
print(bType.value)
}
}
Then this doesn't compile as B is not imported and so BType can't be accessed.
The catch!
However! If you declare an extension in B something like...
extension String {
func doAThingInB() {
print(self)
}
}
Then now... without any changes to the imports and the dependencies, I can now change my app code to...
import Foundation
import A
struct TestType {
func doSomething() {
"Hello, bug!".doAThingInB()
}
}
And this will print out as though the extension is public to the actual App. It sort of "bunny hops" from B, over A and into the app.
I feel like this shouldn't happen at all.
We can't find a way to turn this off or to stop this happening.
Is this a bug?
Is there something we need to do to stop this?
Thanks
I have tried to make use of private module maps to hide the inner framework from being visible to the users of A, but had no luck with it. Could be related to [SR-2896] Private modulemaps do no work properly.
I guess this is the expected behaviour right now. There are multiple proposals on swift.org forums to implement something like you want, for example Namespaces x submodules or a more relevant one #_exported and fixing import visibility.
Relevant parts from the last one:
Today’s Swift is designed more like Java or C# or Python, in that if you import Bar in the implementation of Foo it doesn’t affect clients who import Foo. Or, well, it doesn’t make the top-level names of Bar visible to clients who import Foo.
You still need Bar around, because the compiler doesn’t track whether you’ve used one of its types in Foo’s public interface. (That’s the previous section.)
Extensions in Bar are still made visible to clients who import Foo, because the compiler doesn’t distinguish where extensions come from today.
Operator declarations in Bar are still made visible to clients who import Foo, because the compiler finds operators in a different way than it finds everything else at the top level.
And from one of the last messages:
the general outcome of this discussion is that it's probably not worth doing anything clever for Swift vNext: just add "implementation-only import" and maybe "exported import" and leave the rest alone for now.
I'd be happy to know if there is a workaround for this, but it seems like there is none.
OK... so response from the Swift team...
https://bugs.swift.org/browse/SR-9913
This is something they have known about for a while. And they are not looking to fix it any time soon.
So, yes, it's a bug.
But, no, there isn't any way to fix it.
I guess fixing it would cause more issues than it would fix in terms of breaking changes.

Duplicate interface definition for class SBJsonBase?

I added the Facebook sdk code to my project then I got this error because I already had a json library, so I deleted the Facebook json library from my computer and from the project but I still get this error. I search the whole project for "#interface SBJsonBase" and I only get one result. How can it say it's a duplicate when I only have one interface? Is it including the file twice? Does the search not always find everything?
May be this helps? Delete your derived data and do a clean project, then try to build again
I had a simular problem. It was a small search, but I could solve it without creating a new project etc...
The thing was I had a Class B that was importing Class A.
Then I had a class that imported Class B and also Class A.
When I did this, these problems occured.
Eg. A SOAP webservice Class imports all the Entities that are passed over the web.
Class goToSchoolWebservice.
import "person.h"
import "school.h"
...
Then I had a Singleton class used for caching that had the Logged in Person and also a ref to the webservice class.
import "person.h"
import "goToSchoolWebservice.h"
--> this is where is went wrong!!
So watch out for these circular references. ITs not so easy to detect them!
if your using #include instead of import then use this technique to minimize duplicates: at the begining of your interface (actually right before it) do check for a definition and if not defined then define it and proceed to define your interface. here is an example:
#ifndef __NetworkOptionsViewController__H // check if this has every been imported before
#define __NetworkOptionsViewController__H
#import "blahblah.h"
#interface NetworkOptionsViewController : UITableViewController
{
NSMutableArray* somevariable1;
int somevariable2;
}
#end
#endif
-- for me personally, i got this error though because the file path to my class was wrong. I checked file inspector and my class file was not defined in Classes folder even though the IDE said it was. I deleted them and copied them over again.
For those that still get this error, despite following header import conventions: I got this error from importing a header that had been deleted from the project. The missing header was instead found in an old backup of my project in dropbox (That I made before doing some destructive stuff in Git), and that file caused the circular import.
I solved a similar problem by moving all the imports to the prefix header file.