I created a swift framework and now i want to import it in my application.
I did import BiometricAccessControl in my ViewController but xcode not recognizes my classes.
How can i solved it?
Thanks
Maybe it is a problem of access control policy.
By Default, your type(class,enum,struct) and their member(property,subscript,method)'s access control level is internal,which is visible inside your framework,if you want to expose it(namely,API) to other modules, you could try to add public modifier to your class or their member.For Example:
public class MySwiftComponent {
public var publicInt:Int?
private var privateInt:Int?
internal var internalInt:Int?
}
Totally, there are three access level : public ,internal and private (internal is default)
Related
I start a new project in swift with a workspace. I add a new package in the project called ApplicationCore by using File - New - Package. After i add the new package i see a a file in the package which is automatically created called ApplicationCore.swift with the following code.
//ApplicationCore.swift
public struct ApplicationCore {
public private(set) var text = "Hello, World!"
public init() {
}
}
Then i add another folder called Colors and inside this folder i create a new swift file called AppColors.swift. Here is the code...
//AppColors.swift
import Foundation
public struct AppColors {
public let greenColor = Color.green
}
So i need to access the struct AppColors from within the struct ApplicationCore which exists in the ApplicationCore.swift file. I use this code inside ApplicationCore
public private(set) var AppColorGreen = AppColors.greenColor
I get a message saying
Cannot find 'AppColors' in scope
What am i missing? I am new to swift so any help appreciated.
Actual Path: Sources/ApplicationCore/ApplicationCore.swift and Sources/Colors/AppColors.swift
The problem seems to be that you've put your Colors folder in the wrong place.
For a package that provides a single product (library, executable, etc...), if that product is called X, then you want all of the source code for X to be inside of Source/X. This is how SPM sets up a package initially.
In your case, you have a package, which I suppose is called ApplicationCore, which provides a product/target that is also called ApplicationCore. So all of your source code should go into Source/ApplicationCore.
You don't have to use the same name for the product as for the package, but that is the default for the Package.swift file SPM creates. To change it, you'd need to edit the products and targets arrays in Package.swift, and name the directory in Source to be whatever name you pick for the product.
I am working on a Swift framework which has majority of Swift files and very few Objective C files. Since I don't want my Objective-C files to be available outside the SDK and not even under headers folder, I gave them project access and now use them internally with a module map.
Here is how my modulemap file looks like:
module MySDKPrivate {
header "CardDetails.h"
export *
}
Now, in order to access this CardDetails file, I just need to import MySDKPrivate module in the required Swift class. All good till here.
Now, let's say I have a public class, named Payment.swift. This class is responsible for executing SDK operations partially hidden to the user, hence it is under the project access, so it does not show up in the headers when SDK is distributed.
There are some methods such as authenticate and getSessionExpireDate which are accessed by a PaymentDoor.swift class, which is basically nothing but an extension to Payment class for partial read & write injection, helping to get the minor info in/out of Payment class. Here is the sample signature of PaymentDoor.swift
//Extension to inject data in and out of the Internal Payment.swift
public extension Payment{
}
And here is the Payment.Swift class
import MySDKPrivate
public class Payment {
let username: String
let password: String
let cardDetails: CardDetails
public init(userName: String, password: String, cardNumber: String) {
self.username = userName
self.password = password
let cardDetails = CardDetails()
cardDetails.cardNumber = cardNumber
self.cardDetails = cardDetails
}
public func authenticate() -> Bool{
//Some logic
return true
}
private func generateAuthkey(){
//Should not be accessible with the extension
}
}
This is another reason why I want to keep this Payment class as public and inside project access for headers, because If I make it available as public under headers, SDK user would see the name of my modulemap and all the code in Payment class and could use the objective-c files as well with importing the module map. Although now also the name of the module map comes up by Auto Help but at least it's not visible directly.
I still think there could be a better way to inject data in and out of a public class which hides my module name OR Hiding Objective-C files could be done in a better way may be. If yes, please help !
Swift 3 introduced the new open keyword that I'm using in a framework.
Does an open class in this framework require an open initialiser to be used outside of said framework, or does the init function inherit the open declaration on the class?
For example:
open class OpenClass {
var A: String
init() { // does this init() function need to be marked open?
A = String()
}
}
Side question: do the variables in the open class OpenClass inherit the open nature of their class?
From SE-0117 Allow distinguishing between public access and public overridability:
Initializers do not participate in open checking; they cannot be declared open, and there are no restrictions on providing an initializer that has the same signature as an initializer in the superclass.
You need not and you cannot declare a init method as open:
open class OpenClass {
open init() { // error: only classes and overridable class members can be declared 'open'; use 'public'
}
}
The default access level for all members of a class (properties
and methods) is internal, that applies to open classes as well.
So in Apple documentation:
Any type members added in an extension have the same default access level as type members declared in the original type being extended. If you extend a public or internal type, any new type members you add will have a default access level of internal.
Giving a sub class of UIView extension:
extension UIViewSubClass
{
var helloWorld : String {
get {
return "helloWorld"
}
}
}
This will mark helloWorld as internal, I have no problem, and I cannot see it in my Objective-C based project.
However, if I mark the extension to be public:
public extension UIViewSubClass
{
var helloWorld : String {
get {
return "helloWorld"
}
}
}
Now helloWorld apprears in my Objective-C based code, which means it is marked as public.
However, I don't see Apple mentions this, did it?
I just saw the documentation said a public class will still has implicit internal level.
public class SomePublicClass { // explicitly public class
public var somePublicProperty = 0 // explicitly public class member
var someInternalProperty = 0 // implicitly internal class member
private func somePrivateMethod() {} // explicitly private class member
}
Marking public for extension seems have different effect than marking a Class definition. This makes me confused.
Could someone help me, is this supposed to be so, or this is a sort of swift bug? I am with swift 2.1 and Xcode 7.2
Answer: Yes, placing access level modifiers (in your case, public, specifically) in front of extensions modify the default access level of all new types in the scope of that extension.
Note that the modifier does not affect the access level of the class/struct/etc being extended (only it's members. However, there are things that ought to be considered, as I will discuss below.
In this discussion, I'll post a few important facts regarding regarding access levels in Swift. All these are from the Swift Language Guide - Access Control - Access Levels.
Let's first assure what you've already stated:
All entities in your code (with a few specific exceptions, as
described later in this chapter) have a default access level of
internal if you do not specify an explicit access level yourself.
OK, this goes in line with what you've quoted in you question: any new type members, whether in a class or structure definition, will have a default access level of internal.
Now, lets look at the access level modifier that you can add in front of extensions:
You can extend a class, structure, or enumeration in any access
context in which the class, structure, or enumeration is available.
Any type members added in an extension have the same default access
level as type members declared in the original type being extended. If
you extend a public or internal type, any new type members you add
will have a default access level of internal. If you extend a private
type, any new type members you add will have a default access level of
private.
Alternatively, you can mark an extension with an explicit access level
modifier (for example, private extension) to set a new default access
level for all members defined within the extension. This new default
can still be overridden within the extension for individual type
members.
This sorts things out. We look at your example, and assume that your class UIViewSubClass has access level public (or compile time error, se below):
/* no access level modifier: default access level will be 'internal' */
extension UIViewSubClass
{
// default access level used: internal
var helloWorld : String {
get {
return "helloWorld"
}
}
}
// modify default access level to public
public extension UIViewSubClass
{
// default access level used: public
var helloWorld : String {
get {
return "helloWorld"
}
}
}
With the discussion above in mind, it's expected that your helloWorld in you public extension ... is marked as internal, as this is, in this context, the default access level. In the context of extensions, access level modifiers work differently than when applied to types.
Finally, we should point out that using a public access modifier when extending a non-public class will yield a compile time error in Swift. So in your case above:
If UISubViewClass is an internal or a private class, then the public extension ... on the class will yield an compile time error.
If UISubViewClass is a public class, then adding the public extension will be redundant as the default access modifier of a public class is already, by definition, public.
I'd say that the error described above is not really an error to avoid runtime errors, but rather to avoid redundant (and confusing) code: public member types or private or internal classes will never make use of itspublic` access level.
class MyImplicitlyInternalClass {
private var myExplicitlyPrivateVar = 0
var myImplicitlyInternalVar = 0
public var myExplicitlyPublicVar = 0 // warning, see (Note 1) below
// redundant 'public': can never be accessed publicly
// myExplicitlyPublicVar will behave as 'internal'
}
public extension MyImplicitlyInternalClass { // error, see (Note 2)
var myNewVarIsInternal : Int { get { return 0 } }
}
/* (Note 1) Compile type warning:
"Declaring a public var for an internal class."
(Note 2) Compile time error:
"Extension of internal class cannot be declared public."
Summary: in theory, these two above are the same type of
'faults', but only the latter is flagged as and error. */
Hence, it only ever makes sense to use the access level modifiers on extensions to make the default access level more restrictive, i.e., using internal extension ... of a public class, or private extension or an internal class.
The documentation only mentions nested types, but it's not clear if they can be used as namespaces. I haven't found any explicit mentioning of namespaces.
I would describe Swift's namespacing as aspirational; it's been given a lot of advertising that doesn't correspond to any meaningful reality on the ground.
For example, the WWDC videos state that if a framework you're importing has a class MyClass and your code has a class MyClass, those names do not conflict because "name mangling" gives them different internal names. In reality, however, they do conflict, in the sense that your own code's MyClass wins, and you can't specify "No no, I mean the MyClass in the framework" — saying TheFramework.MyClass doesn't work (the compiler knows what you mean, but it says it can't find such a class in the framework).
My experience is that Swift therefore is not namespaced in the slightest. In turning one of my apps from Objective-C to Swift, I created an embedded framework because it was so easy and cool to do. Importing the framework, however, imports all the Swift stuff in the framework - so presto, once again there is just one namespace and it's global. And there are no Swift headers so you can't hide any names.
EDIT: In seed 3, this feature is now starting to come online, in the following sense: if your main code contains MyClass and your framework MyFramework contains MyClass, the former overshadows the latter by default, but you can reach the one in the framework by using the syntax MyFramework.MyClass. Thus we do in fact have the rudiments of a distinct namespace!
EDIT 2: In seed 4, we now have access controls! Plus, in one of my apps I have an embedded framework and sure enough, everything was hidden by default and I had to expose all the bits of the public API explicitly. This is a big improvement.
Answered by SevenTenEleven in the Apple dev forum:
Namespaces are not per-file; they're per-target (based on the
"Product Module Name" build setting). So you'd end up with something
like this:
import FrameworkA
import FrameworkB
FrameworkA.foo()
All Swift declarations are considered to be part of
some module, so even when you say "NSLog" (yes, it still exists)
you're getting what Swift thinks of as "Foundation.NSLog".
Also Chris Lattner tweeted about namespacing.
Namespacing is implicit in Swift, all classes (etc) are implicitly
scoped by the module (Xcode target) they are in. no class prefixes
needed
Seems to be very different what I have been thinking.
While doing some experimentation with this I ended up creating these "namespaced" classes in their own files by extending the root "package". Not sure if this is against best practices or if it has any implications I'm mot aware of(?)
AppDelegate.swift
var n1 = PackageOne.Class(name: "Package 1 class")
var n2 = PackageTwo.Class(name: "Package 2 class")
println("Name 1: \(n1.name)")
println("Name 2: \(n2.name)")
PackageOne.swift
import Foundation
struct PackageOne {
}
PackageTwo.swift
import Foundation
struct PackageTwo {
}
PackageOneClass.swift
extension PackageOne {
class Class {
var name: String
init(name:String) {
self.name = name
}
}
}
PackageTwoClass.swift
extension PackageTwo {
class Class {
var name: String
init(name:String) {
self.name = name
}
}
}
Edit:
Just found out that creating "subpackages" in above code wont work if using separate files. Maybe someone can hint on why that would be the case?
Adding following files to the above:
PackageOneSubPackage.swift
import Foundation
extension PackageOne {
struct SubPackage {
}
}
PackageOneSubPackageClass.swift
extension PackageOne.SubPackage {
class Class {
var name: String
init(name:String) {
self.name = name
}
}
}
Its throwing a compiler error:
'SubPackage' is not a member type of 'PackageOne'
If I move the code from PackageOneSubPackageClass.swift to PackageOneSubPackage.swift it works. Anyone?
Edit 2:
Fiddling around with this still and found out (in Xcode 6.1 beta 2) that by defining the packages in one file they can be extended in separate files:
public struct Package {
public struct SubPackage {
public struct SubPackageOne {
}
public struct SubPackageTwo {
}
}
}
Here are my files in a gist:
https://gist.github.com/mikajauhonen/d4b3e517122ad6a132b8
I believe this is achieved using:
struct Foo
{
class Bar
{
}
}
Then it can be accessed using:
var dds = Foo.Bar();
Namespaces are useful when you need to define class with the same name as class in existing framework.
Suppose your app has MyApp name, and you need to declare your custom UICollectionViewController.
You don't need to prefix and subclass like this:
class MAUICollectionViewController: UICollectionViewController {}
Do it like this:
class UICollectionViewController {} //no error "invalid redeclaration o..."
Why?. Because what you've declared is declared in current module, which is your current target. And UICollectionViewController from UIKit is declared in UIKit module.
How to use it within current module?
var customController = UICollectionViewController() //your custom class
var uikitController = UIKit.UICollectionViewController() //class from UIKit
How to distinguish them from another module?
var customController = MyApp.UICollectionViewController() //your custom class
var uikitController = UIKit.UICollectionViewController() //class from UIKit
Swift uses modules much like in python (see here and here) and as #Kevin Sylvestre suggested you can also use the nested types as namespaces.
And to extend the answer from #Daniel A. White, in WWDC they were talking about the modules in swift.
Also here is explained:
Inferred types make code cleaner and less prone to mistakes, while
modules eliminate headers and provide namespaces.
You can use extension to use the mentioned structs approach for namespacing without having to indent all of your code towards the right. I've been toying with this a bit and I'm not sure I'd go as far as creating Controllers and Views namespaces like in the example below, but it does illustrate how far it can go:
Profiles.swift:
// Define the namespaces
struct Profiles {
struct Views {}
struct ViewControllers {}
}
Profiles/ViewControllers/Edit.swift
// Define your new class within its namespace
extension Profiles.ViewControllers {
class Edit: UIViewController {}
}
// Extend your new class to avoid the extra whitespace on the left
extension Profiles.ViewControllers.Edit {
override func viewDidLoad() {
// Do some stuff
}
}
Profiles/Views/Edit.swift
extension Profiles.Views {
class Edit: UIView {}
}
extension Profiles.Views.Edit {
override func drawRect(rect: CGRect) {
// Do some stuff
}
}
I haven't used this in an app since I haven't needed this level of separation yet but I think it's an interesting idea. This removes the need for even class suffixes such as the ubiquitous *ViewController suffix which is annoyingly long.
However, it doesn't shorten anything when it's referenced such as in method parameters like this:
class MyClass {
func doSomethingWith(viewController: Profiles.ViewControllers.Edit) {
// secret sauce
}
}
Even though it is possible to implement namespaces using Framework and Libraries but the best solution is to use local packages using Swift Package Manager. Besides having access modifiers, this approach has some other benefits. As in Swift Package Manager, the files are managed based on the directory system, not their target member ship, you won't have to struggle with merge conflicts that arise frequently in teamworks. Furthermore, there is no need to set file memberships.
To check how to use local Swift packages refer to the following link:
Organizing Your Code with Local Packages
In case anyone was curious, as of June 10th 2014, this is a known bug in Swift:
From SevenTenEleven
"Known bug, sorry! rdar://problem/17127940 Qualifying Swift types by their module name doesn't work."