How can I access private property outside that class in Swift? [duplicate] - swift

This question already has answers here:
Read-Only properties
(3 answers)
Closed 9 months ago.
Here I have a class and make its properties private to prevent from modifications by accident.
class Article {
private var lineIndex: [Int] = []
private var text: [String] = []
....
}
I know I can write a function like func text(_ index: Int) -> String to get its value at index. But when I call it, article1.text(2) would be weird. Because it's less clear to indicate 2 is an index than what an array does like article1.text[2]. So can I use getter or something else instead, while keeping the clear syntax like text[2]. It couldn't be better if you can offer some examples.

You can use one of these ways:
with private(set), which allows editable inside the class:
class Article {
private(set) var text: [String] = []
...
}
with get only computed property (this is the same like your get function)
class Article {
var _text: [String] {
return text
}
}

Related

What's the difference of `private` and `fileprivate` class in the same file in Swift? [duplicate]

This question already has an answer here:
In Swift 3, is there a difference between 'private class Foo' and 'fileprivate class Foo' in regards to member variables?
(1 answer)
Closed 2 years ago.
As the sample code here, what's the difference of private and fileprivate class in the same file in Swift?
// ViewController.swift
private class A {
var name: String = ""
let d = B.D()
}
fileprivate class B {
var name: String = ""
private let c = C()
private class C {
var number: String = ""
}
fileprivate let d = D()
fileprivate class D {
var number: String = ""
}
}
Since class A and B are in the sample file, A can't be any more private then B, right?
Sorry this is a very picky question, but I just want to confirm it.
Access modifiers in swift have been charged a few times during the past few releases.
For now, let me suggest a code sample instead of explanation first:
All code in one file:
fileprivate class Foo {
private var someVariablePrivate: Int?
fileprivate var someVariableFileprivate: Int?
private func makeBar() { }
fileprivate func makeFoo() { }
}
extension Foo {
func bar() {
let value = someVariablePrivate // OK
let value2 = someVariableFileprivate // OK
}
}
private class Foofoo: Foo {
override func makeFoo() {
// OK
}
override func makeBar() {
// NOK, because private
}
}
class Bar {
func foo() {
let object = Foo()
let value = object.someVariableFileprivate // OK
let value2 = object.someVariablePrivate // NOK - because it private to that class
}
}
Previously, private restrict access only to type definition, but within few lates version of Swift, it has been modified and updated, so even extension of same type can use private variables
As Apple mention:
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.
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.
we could compare a bit this modifiers:
why do we ned both of them:
You may, however, want to mark some parts of your code as file private
or private in order to hide their implementation details from other
code within the app’s module.
When to use fileprivate
Although the keywords are almost the same, there is a clear difference in their use cases. Fileprivate access restricts the use of an entity within the same defined source file. The only reason you would use fileprivate is when you want to access your code within the same file from different classes or structs.
When to use private
The private keyword is used a lot more and restricts the use of an entity to the enclosing declaration and its extensions. The extensions, however, have to be defined within the same file. In other words, private declarations will not be visible outside the file. You can use this keyword to only expose the minimal code needed to interact with the entity. This will improve readability and makes it easier to use and understand your code for others.
your question: Since class A and B are in the sample file, A can't be any more private then B, right?
In case of class A with private access specifier it won't be accessible outside it's declared scope.
In case of class B it will be accessible to the class A but it's private properties won't be accessible in class A
For more information, you can refer to this interesting article:
https://www.avanderlee.com/swift/fileprivate-private-differences-explained/#when-to-use-private

Get a Swift class's property name as a String [duplicate]

This question already has answers here:
Get a Swift Variable's Actual Name as String
(7 answers)
Closed 5 years ago.
How do I get the property name as a string?
class Person {
var firstName: String
var lastName: String
var downloading: Bool
func excludePropertiesFromCloud() -> [String] {
return //here I want to return ["downloading"]
}
}
I would like to avoid having to type return ["downloading"] to prevent errors if the name of the variable changes later on.
To get the class name you can use String(describing: Person.self), so I am looking at something similar for properties.
Note:
Although the title of the question is very similar to Get a Swift Variable's Actual Name as String, it is clear that the accepted answer in the original question returns the value of the property and does not answer this straightforward question. The original question is the first to come up on any google search with "Swift get property name", and the answer answers something else, as pointed to by #MarqueIV. This is why I created this question
If you are ok with making your properties #objc you can get the property name like so:
class Person {
#objc var firstName: String
var lastName: String
var downloading: Bool
func excludePropertiesFromCloud() -> [String] {
return [#keyPath(firstName)]
}
}

Expected declaration when adding values to a Swift dictionary [duplicate]

This question already has answers here:
swift compiler shows Expected declaration error? [duplicate]
(3 answers)
Expected Declaration Error using Swift
(1 answer)
Closed 5 years ago.
I get the error "expected declaration" on the last line when trying to add values to the dictionary tablesBooked.
class BookingSystem {
var tablesBooked = Dictionary<Int, String>()
var table = Table(tableID: 1 , tableCapacity: 2, status: "A")
var bookings = [Booking]()
tablesBooked.setValue(table.status, forKey: table.tableID)
}
You get this error because your line setValue cannot just live here inside your class without being inside a method. Of course here it really depends on what (and how) you want to accomplish, but you could put it in the init() method of your BookingSystem class, or you could build your own custom init().
Here is how it would look like:
import Foundation
class Booking {
// Some interesting things here
}
class Table : NSObject {
// MARK: Properties
var tableID: Int
var tableCapacity: Int
var status: String
// MARK: Initializers
init(tableID: Int, tableCapacity: Int, status: String) {
self.tableID = tableID
self.tableCapacity = tableCapacity
self.status = status
}
}
class BookingSystem {
// MARK: Properties
var tablesBooked = [Int: String]()
var table = Table(tableID: 1 , tableCapacity: 2, status: "A")
var bookings = [Booking]()
// MARK: Initializers
init() {
// I am not sure what you are trying to do here, but anyway you should add it in a custom method or your init. If I were to use the code in your example, you would add this here:
tablesBooked[table.tableID] = table.status
}
// ...
}
I added the Table class here on purpose, just to show you an example on how to create your own custom init.
Also, another thing worth mentioning here is that Swift Dictionaries don't have a setValue:forKey: method. Instead, to add an object to your Dictionary, you should use:
yourDictionnary["yourKey"] = yourValue
Hope it helps, and if you have any questions just feel free asking :)
Use init method:
class BookingSystem {
var tablesBooked = Dictionary<Int, String>()
var table = Table(tableID: 1 , tableCapacity: 2, status: "A")
var bookings = [Booking]()
init() {
tablesBooked.setValue(table.status, forKey: table.tableID)
}
}

How to mute the warning of "never mutated" in Swift? [duplicate]

This question already has answers here:
Why constant constraints the property from a structure instance but not the class instance?
(2 answers)
Swift constant UIView never mutated warning
(1 answer)
UITableViewCell var "table view cell" was never mutated
(1 answer)
Closed 5 years ago.
Regarding duplicate flag: This question is different from the flagged question as I am asking about how to mute the warnings as I was not aware of the concept of Swift. The provided below answer helps me understand the very basic nature of Swift. Thus this question should not flagged as duplicate.
I have a class name Person having following variables.
private var _id:String = ""
var id:String {
get {
return _id
}
set (newId) {
_id = newId
}
}
private var _name:String = ""
var name:String {
get {
return _name
}
set (newName) {
_name = newName
}
}
private var _signedDate:Date? = nil
var signedDate:Date {
get {
return _signedDate!
}
set(newDate) {
_signedDate = newDate
}
}
These private var's are going to update with a setter.
So while creating an object for the Person class, I am writing this code.
var p1 = Person()
p1.id = "1"
p1.name = "Hemang"
array.append(p1)
Maybe later, I will update the value of signedDate with a setter.
So I should not create this object with let.
However, it's showing me this warning:
Variable 'p1' was never mutated; consider changing to 'let' constant.
How to mute this warning?
Please let me know if you need more information on this.
Because actually you don't change the Person object,
With let you can change the properties of the object. But you can't change the object it self.
So change your code to what the warning lead you.
And of course you can try before asking this question.

Differences between "static var" and "var" in Swift

What is the main difference between "static var" and "var" in Swift? Can someone explain this difference to me, possibly with a little example?
static var belongs to type itself while var belongs to instance (specific value that is of specific type) of type. For example:
struct Car {
static var numberOfWheels = 4
var plateNumber: String
}
Car.numberOfWheels = 3
let myCar = Car(plateNumber: "123456")
All cars has same amount of wheels. An you change it on type Car itself.
In order to change plate number you need to have instance of Car. For example, myCar.
I'll give you a very nice Swifty example based on this post. Though this is a bit more sophisticated.
Imagine you have a project in which you have 15 collectionViews in your app. For each you have to set the cellIdentifier & nibName. Do you really want to rewrite all code for your that 15 times?
There is a very POP solution to your problem:
Let's help ourselves by writing a protocol which returns a string version of our ClassName
protocol ReusableView: class {
static var defaultReuseIdentifier: String { get }
}
extension ReusableView where Self: UIView {
static var defaultReuseIdentifier: String {
return String(Self)
}
}
extension BookCell : ReusableView{
}
The same for the nibName of each custom cell you have created:
protocol NibLoadableView: class {
static var nibName: String { get }
}
extension NibLoadableView where Self: UIView {
static var nibName: String {
return String(Self)
}
}
extension BookCell: NibLoadableView {
}
so now where ever I need nibName I would just do
BookCell.nibName
And where ever I need cellIdentifier I would just do:
BookCell.defaultReuseIdentifier
Now specifically to your question. Do you think we need to change the cellIdentifier per each new instance of BookCell?! No! All cells of BookCell will have the same identifier. It's not something that would change per instance. As a result it's been made static
While I did answer your question, the solution to reducing the number of lines for the 15 collectionViews can still be significantly improved so do see the blog post linked.
That blog post has actually been turned into a video by NatashaTheRobot
A static var is property variable on a struct versus an instance of the struct. Note that static var can exist for an enum too.
Example:
struct MyStruct {
static var foo:Int = 0
var bar:Int
}
println("MyStruct.foo = \(MyStruct.foo)") // Prints out 0
MyStruct.foo = 10
println("MyStruct.foo = \(MyStruct.foo)") // Prints out 10
var myStructInstance = MyStruct(bar:12)
// bar is not
// println("MyStruct.bar = \(MyStruct.bar)")
println("myStructInstance = \(myStructInstance.bar)") // Prints out 12
Notice the difference? bar is defined on an instance of the struct. Whereas foo is defined on the struct itself.