I have seen some code in swift some thing like below. It used in a Framework, I'm trying to replicate the same code, as we knows getting errors. But how it is used in Framework?.
If we see the below code Strings, Localized and String code its not implementing init or extension of String replace(::) not implemented. What this code means and how to use in project as TopLevel Objects?
I can able to access this code by importing Framework, and I can make changes to that code.
Here is the code.
struct Profile { }
extension Profile {
public struct Strings {
public var title: Localized
public init()
}
}
public struct Localized : ExpressibleByStringLiteral {
public init(value: String)
}
extension String {
public func replace(_ offset: Int = 4, with symbol: Character = "*") -> String
}
What this code means
It isn't code. It's a header. It shows the declarations of some structs and methods, but not their implementations. It's basically a table of contents for you, the programmer, describing what structs there are and what methods they have. But you are not shown the actual code for how those methods are written. As you yourself have said, the framework is private.
I have a small iOS application which relies on CoreData.
I have at the moment two entities, "Product" and "StorageLocation".
There is a one-to-many relationship between them.
I generated the classes manually; the Model Editor also shows the correct class name.
When trying to save a new "Product" which contains a relationship to a "StorageLocation" I get this error:
-[StorageLocation addProductsObject:]: unrecognized selector sent to instance 0x60000389d280"
The generated NSManagedObject class is as follows:
import Foundation
import CoreData
extension StorageLocation {
#nonobjc public class func fetchRequest() -> NSFetchRequest<StorageLocation> {
return NSFetchRequest<StorageLocation>(entityName: "StorageLocation")
}
#NSManaged public var id: UUID?
#NSManaged public var name: String?
#NSManaged public var products: NSSet?
}
// MARK: Generated accessors for products
extension StorageLocation {
#objc(addProductsObject:)
#NSManaged public func addToProducts(_ value: Product)
#objc(removeProductsObject:)
#NSManaged public func removeFromProducts(_ value: Product)
#objc(addProducts:)
#NSManaged public func addToProducts(_ values: NSSet)
#objc(removeProducts:)
#NSManaged public func removeFromProducts(_ values: NSSet)
}
extension StorageLocation : Identifiable {
}
Problem, as error says, is the method "addToProducts" which I invoke like this:
let newItem = Product(context: viewContext)
newItem.id = id
newItem.name = name
newItem.qty = Int32(actualQty)
newItem.expDate = expDate
location.addToProducts(newItem)
I also checked if the model matches with the classes, no error found.
Any idea/hint?
Thanks
Marco
It's hard to be sure but since you generated the file manually, it might be that it didn't get added to the app target. That would mean the code exists but isn't being compiled as part of the app. Try this:
Click on the file in the file navigator on the left side of the window.
Bring up the "file inspector" tab on the right. That's the one you get if you press cmd-opt-1.
Look in the inspector where it says "target membership". This should list the app plus any test targets, as well as app extensions if you have any.
Make sure your app's name is checked in the target membership list.
If it wasn't checked, and you check it, your code will probably work.
I've been looking through the swift docs and working through some examples around encapsulation, and am unsure about the behaviour that I'm seeing. I've looked for similar questions on stack, looked through the doc and looked through some tutorials (see the link below) and although this is a trivial question can't find an answer (possibly as Swift has changed?)
Creating a simple Struct representing a queue:
struct Queue<Element> {
private var elements = [Element]()
mutating func enqueue(newElement: Element) {
elements.append(newElement)
}
mutating func dequeue() -> Element? {
guard !elements.isEmpty else {
return nil
}
return elements.remove(at: 0)
}
}
Is later extended by:
extension Queue {
func peek() -> Element? {
return elements.first
}
}
But of course elements is inaccessible due to the private protection level.
It works by changing the access of elements to fileprivate - but why?
My understanding was that extensions were part of the enclosing type, and looking around the web it seems that is used to work this way https://www.andrewcbancroft.com/2015/04/22/3-nuances-of-swift-extensions/
So is my understanding of visibility wrong, or has Swift changed?
From the Swift's book:
Private access restricts the use of an entity to the enclosing declaration. Use private access to hide the implementation details of a specific piece of functionality when those details are used only within a single declaration.
So a private variable is only accessible within the set of curly brackets where it's defined. Swift's Access Control has never been like those of C++
, Java or C#.
With release of Swift 4 this has been changed if the extension is implemented within the same file. You can refer the doc here
Private Member in Extension
Example below is from Swift 4
protocol SomeProtocol {
func doSomething()
}
struct SomeStruct {
private var privateVariable = 12
}
extension SomeStruct: SomeProtocol {
func doSomething() {
print(privateVariable)
}
}
This article has been helpful in understanding the new access specifiers in Swift 3. It also gives some examples of different usages of fileprivate and private.
My question is - isn't using fileprivate on a function that is going to be used only in this file the same as using private?
fileprivate is now what private used to be in earlier
Swift releases: accessible from
the same source file. A declaration marked as private can now only be accessed within the lexical scope it is declared in.
So private is more restrictive than fileprivate.
As of Swift 4, private declarations inside a type are accessible to extensions of the same type if the extension is defined in the same source file.
Example (all in one source file):
class A {
private func foo() {}
fileprivate func bar() {}
func baz() {
foo()
bar()
}
}
extension A {
func test() {
foo() // Swift 3: error: use of unresolved identifier 'foo'
// Swift 4: no error because extension is in same source file
bar()
}
}
let a = A()
a.foo() // error: 'foo' is inaccessible due to 'private' protection level
a.bar()
The private foo method is accessible only within the scope of
the class A { ... } definition. It is not even accessible from
an extension to the type (in Swift 3, see the second note below for
changes in Swift 4).
The file-private bar method is accessible from the same source file.
Notes:
The proposal SE-0159 – Fix Private Access Levels suggested to revert to the Swift 2 semantics in Swift 4. After a lengthy and controversial discussion on the swift-evolution mailing list, the proposal was rejected.
The proposal SE-0169 – Improve Interaction Between private Declarations and Extensions suggests to make private
declarations inside a type accessible to extensions of the same type
if the extension is defined in the same source file.
This proposal was accepted and implemented in Swift 4.
I just draw a diagram about private, fileprivate, open and public
Hope it can quickly help you , for text description please refer to Martin R 's answer
[ Update Swift 4, 5 ]
Updated for Swift 5
Private vs FilePrivate
For better clarity paste the code snippet in Playground
class Sum1 {
let a: Int!
let b: Int!
private var result: Int?
fileprivate var resultt: Int?
init(a : Int, b: Int) {
self.a = a
self.b = b
}
func sum(){
result = a + b
print(result as! Int)
}
}
let aObj = Sum1.init(a: 10, b: 20)
aObj.sum()
aObj.resultt //File Private Accessible as inside same swift file
aObj.result //Private varaible will not be accessible outside its definition except extensions
extension Sum1{
func testing() {
// Both private and fileprivate accessible in extensions
print(result)
print(resultt)
}
}
//If SUM2 class is created in same file as Sum1 ---
class Sum2{
func test(){
let aSum1 = Sum1.init(a: 2, b: 2)
// Only file private accessible
aSum1.resultt
}
}
Note: Outside of Swift file both private and fileprivate are not accessible.
A practical rule of thumb is that you use private for variables, constants, inner structs and classes that are used only inside the declaration of your class / struct. You use fileprivate for things that are used inside of your extensions within the same file as your class/struct but outside of their defining curly braces (ie. their lexical scope).
class ViewController: UIViewController {
#IBOutlet var tableView: UITableView!
//This is not used outside of class Viewcontroller
private var titleText = "Demo"
//This gets used in the extension
fileprivate var list = [String]()
override func viewDidLoad() {
navigationItem.title = titleText
}
}
extension ViewController: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return list.count
}
}
In Swift 4.0, Private is now accessible in extension but within same file. If you declare/define extension in other file, then your private variable will not be accessible to your extension**
File Private
File-private access restricts the use of an entity to its own defining source file. Use file-private access to hide the implementation details of a specific piece of functionality when those details are used within an entire file.
Syntax: fileprivate <var type> <variable name>
Example: fileprivate class SomeFilePrivateClass {}
Private
Private access restricts the use of an entity to the enclosing declaration, and to extensions of that declaration that are in the same file. Use private access to hide the implementation details of a specific piece of functionality when those details are used only within a single declaration.
Syntax: private <var type> <variable name>
Example: private class SomePrivateClass {}
Here is more detail about all access levels: Swift - Access Levels
Look at this images:
File: ViewController.swift
Here extension and view controller both are in same file, hence private variable testPrivateAccessLevel is accessible in extension
File: TestFile.swift
Here extension and view controller both are in different files, hence private variable testPrivateAccessLevel is not accessible in extension.
Here class ViewController2 is a subclass of ViewController and both are in same file. Here private variable testPrivateAccessLevel is not accessible in Subclass but fileprivate is accessible in subclass.
Although #MartinR's and #StephenChen's answer are perfect, Swift 4 changes things a little bit.
Private is now considered as private to a class in which it is declared and also to its extensions.
FilePrivate is considered to be private in that file be it a class in which the variable is defined, it's extension, or any other classes defined in that same file.
filePrivate - access controll level is within the file.
case 1: If we create extension with in same class file and try to access fileprivate function or fileprivate property in its extension - access allowed
case 2: If we create a extension of class in new file - And now try to access fileprivate function or fileprivate property - access not allowed
private - access control level is with in lexical scope
case 1: If property or function is declared as private in class - then scope is by default the class.
case 2: if private instance is declared with in function body - then scope of instance is limited to function body.
This is the explanation for swift 4. For swift 3, the difference is the private. swift 3 private cannot be accessed by its extension, only Class A itself can access.
After swift 4, fileprivate becomes a bit redundant, because person normally will not define the subclass in the same file. Private should be enough for most cases.
In the following example, language constructs modified by private and fileprivate seem to behave identically:
fileprivate func fact(_ n: Int) -> Int {
if (n == 0) {
return 1
} else {
return n * fact(n - 1)
}
}
private func gauss(_ n: Int) -> Int {
if (n == 0) {
return 0
} else {
return n + gauss(n - 1)
}
}
print(fact(0))
print(fact(5))
print(fact(3))
print(gauss(10))
print(gauss(9))
This is according to intuition, I guess. But, is there any exception?
Kindest regards.
class Privacy {
fileprivate(set) var pu:Int {
get {
return self.pr
}
set {
self.pr = newValue
}
}
private var pr:Int = 0
fileprivate var fp:Int = 0
func ex() {
print("\(self.pu) == \(self.pr) and not \(self.fp)")
}
}
extension Privacy {
func ex2() {
self.pu = 5
self.ex()
}
}
I like this because it is super simple for ivars.
Try changing fileprivate to private (and vice versa) and see what happens on compile...
In my Swift library EVCloudKitDao I do a lot with reflection. Because of that I have set my base class of my data objects to NSObject. Now after the upgrade to Xcode 6.3 I get an error on the 2 functions for getting the hash and the description of the object. The description function was a nice to have, but i do need the hash to make my objects working with a Set.
Here is the code that I have
public class EVCloudKitDataObject : NSObject, NSCoding, Printable, Hashable, Equatable {
public func hash() -> Int {
return self.hashValue
}
public func description() -> String {
return EVReflection.description(self)
}
}
The errors that I get is:
/Users/evermeer/Desktop/dev/GitHub/EVCloudKitDao/AppMessage/AppMessage/CloudKit/EVCloudKitDataObject.swift:106:17:
Method 'hash()' with Objective-C selector 'hash' conflicts with getter
for 'hash' from superclass 'NSObject' with the same Objective-C
selector
/Users/evermeer/Desktop/dev/GitHub/EVCloudKitDao/AppMessage/AppMessage/CloudKit/EVCloudKitDataObject.swift:86:17:
Method 'description()' with Objective-C selector 'description'
conflicts with getter for 'description' from superclass 'NSObject'
with the same Objective-C selector
Does anyone know how I could solve this?
You can not use override.
As the error says, in both cases there's a naming conflict between a property and a method. The most obvious way to fix is by turning your 2 methods into properties:
public override var hash: Int {
return self.hashValue
}
public override var description: String {
return EVReflection.description(self)
}
which can also be written as:
public override var hash:Int {
get {
return self.hashValue
}
}
public override var description : String {
get {
return EVReflection.description(self)
}
}
The reason why it worked in the previous version is most likely because of this:
Swift now detects discrepancies between overloading and overriding in the Swift type system and the effective behavior seen via the Objective-C runtime.
Read more in the release notes (search for 18391046 and 18383574)