Pass value to a private property - ios

I have a couple of private properties defined like so..
private var tableConfig : TableViewConfig<Company, CompanyCell>?
private var tabledata = [Company]() {
didSet {
tableConfig?.items = tabledata
}
}
Now there are 2 other properties defined like so...
var model: Model?
var companyCell: TableviewCell?
Now, if get the value in model as Industry and the value in companyCell as IndustryCell, how can I update these values to private var tableConfig : TableViewConfig.... and private var tabledata = [Company]().... so that they will ultimately have the values like so..
private var tableConfig : TableViewConfig<Industry, IndustryCell>?
private var tabledata = [Industry]() {
didSet {
tableConfig?.items = tabledata
}
}

you can use a get set variabile to achieve this result
var _tabledata: [Industry] {
get {
return tabledata
}
set {
tabledata = newValue
}
}

As the attribute private implies properties and functions declared as private can only be accessed within the scope they are declared.
You have two options:
Change the access control to fileprivate (if the caller is in the same file) or internal or lower restriction.
Add an internal or lower restriction computed property or method in the scope of the private property to set it.

You can expose an init() or a method to set the value of private properties, i.e.
class SampleClass {
private var tableConfig : TableViewConfig<Company, CompanyCell>?
private var tabledata = [Company]() {
didSet {
tableConfig?.items = tabledata
}
}
init(tableData: [Company]) {
self.tabledata = tabledata
}
func add(item: Company) {
self.tabledata.append(item)
}
}
You can create an init in case you want to initialise your private variable and use a method in case you want to update the private variables.

Related

How do you expose a closure from within a #propertywrapper?

I am trying to write a property wrapper to bind two variables together. The problem I am having is that when I call the projectedValue property my closure returns nil. I want to be able to assign a value to the closure once the value of the observed item is changed.
This is my property wrapper class.
#propertyWrapper
class State<Instance> {
typealias projectedClosure = (Instance) ->Void
init(wrappedValue: Instance) {
self.instance = wrappedValue
}
var projectedValue : Binding<Instance> {
Binding<Instance>(value: instance)
}
private var instance : Instance {
didSet{
projectedValue.value = instance
}
}
var wrappedValue: Instance {
get{
return instance
}
set{
instance = newValue
}
}
}
The propertyWrapper projects this class
class Binding<Element> {
var handler : ((Element)->Void)?
var value :Element {
didSet{
guard let handlerClosure = handler else {
print("Handler is null")
return
}
handlerClosure(value)
}
}
init(value:Element) {
self.value = value
}
}
Finally, I am implementing this in a playground before porting it over into my actual project. This is how I am executing the methods.
class TestPropertyWrapperObserver {
#State var name : String
init(name:String) {
self.name = name
}
}
var test = TestPropertyWrapperObserver(name: "Thomas")
var ryan = "ryan"
test.$name.handler = { item in
ryan = item
print(item)
}
test.name = "bradly"
test.name = "fake"
print(ryan)
My print log is:
Handler is null
Handler is null
ryan
Your mistake is that you made projectedValue a computed property, so every time you do this:
projectedValue.value = instance
a new Binding instance is created.
Instead, you should make projectedValue a stored property, and initialise it in init, once:
init(wrappedValue: Instance) {
self.instance = wrappedValue
projectedValue = Binding<Instance>(value: instance)
}
let projectedValue : Binding<Instance>

Setters and Getters with Generics Swift

I was wondering if there is a way to do this in a better way with generics. I have this singleton which needs a setter and another getter for every object. Plus, I have to check that the property is not nil in every getter, which is a lot of repeated code. ex:
class DataManager : NSObject {
private override init(){}
private var postData : [PostModel]?
private var userData : [UserModel]?
private var commentsData : [CommentsModel]?
private var photosData : [PhotosModel]?
private var albumsData : [AlbumsModel]?
private var todosData : [TodosModel]?
static let shared = DataManager()
//MARK : Setters
func setUserData(data : [UserModel]) {
self.userData = data
}
func setPostData(data : [PostModel]) {
self.postData = data
}
func setCommentsData(data : [CommentsModel]) {
self.commentsData = data
}
func setAlbumsData(data : [AlbumsModel]) {
self.albumsData = data
}
func setPhotosData(data : [PhotosModel]) {
self.photosData = data
}
func setTodosData(data : [TodosModel]) {
self.todosData = data
}
//MARK : Getters
func getUserData() -> [UserModel]? {
if self.userData != nil {
return self.userData!
}
return nil
}
func getPostData() -> [PostModel]? {
if self.postData != nil {
return self.postData!
}
return nil
}
func getCommentsData() -> [CommentsModel]? {
if self.commentsData != nil {
return self.commentsData!
}
return nil
}
func getAlbumsData() -> [AlbumsModel]? {
if self.albumsData != nil {
return self.albumsData!
}
return nil
}
func getPhotosData() -> [PhotosModel]? {
if self.photosData != nil {
return self.photosData!
}
return nil
}
func getTodosData() -> [TodosModel]? {
if self.todosData != nil {
return self.todosData!
}
return nil
}
}
I was wondering if all this logic could be done in one single method, maybe using generics?
If you want to force all object to set as a none optional and also get as a none optional, you don't need to define them as optional at the first place:
So instead of:
private var postData : [PostModel]?
you should have:
private var postData = [PostModel]()
This will gives you an empty none optional array and it can not be set or get as an optional.
If you want them to be nil before someone get them (for memory management or etc.), You can make them lazy:
private lazy var postData = [PostModel]()
So now postData will be nil until someone tries to read the value of it.
If you need to do some extra job when someone tries to set one of these, you can observe for changes before set and after set of the value:
private var postData = [PostModel]() {
willSet { /* right before the value is going to set */ }
didSet { /* right after the value is set */ }
}
Note that lazy properties can not have observers
So seems like you don't have any of the functions at all. And you can refactor your code to something like this:
class DataManager : NSObject {
private override init(){}
lazy var postData = [PostModel]()
lazy var userData = [UserModel]()
lazy var commentsData = [CommentsModel]()
lazy var photosData = [PhotosModel]()
lazy var albumsData = [AlbumsModel]()
lazy var todosData = [TodosModel]()
}

DidSet not working in init function swift 3

I have already seen
Is it possible to allow didSet to be called during initialization in Swift?
for me it is not working..
I am working in project where I have created class below
protocol FileManagerHelper {
var fileName:String {get}
var fileCategory:FileCategory {get set}
var isFileExitsAtPath:Bool {get}
var filePath:String {get}
var fileType:FileTypes {get set}
}
class FileManager:FileManagerHelper {
// Other property
//STORED PROPERY INIT WHEN OBJECT WILL CREATED WITH FileCategory OBJECT
var fileCategory:FileCategory {
didSet {
switch fileCategory {
case .XYZ:
print("Test")
... other cases
}
}
required init(fileCategory:FileCategory,fileType:FileTypes = .Image) {
self.fileCategory = fileCategory
self.path = self.folderPath + self.fileName
}
}
did set method is not calling of fileCategory
NOTE: I don't want to give default value , I want to pass it runtime from init method
Tries
1) defer
use of self in method called $defer before all stored property are initialised
2) Create custom method that will assign that value and call it from init
private func setCategory(with category:FileCategory) {
self.fileCategory = category
}
Use of method call setCategory before stored property ...
I know that all stored property should be initialised before instance created. Till that instance will not been created so i won't call methods (using self) may be that why above solution not working
Please help me if any one have idea
For me, using the defer is better readable.
import Foundation
class A {
var b: String {
didSet {
print("didSet called with value: \(b)")
}
}
init(x: String) {
self.b = x
defer { self.b = x }
}
}
let a = A(x: "It's Working!") // didSet called with value: It's Working!
print(a.b) // It's Working
One way to solve this is to extract the didSet logic into a separate method and call this method from both didSet and init:
class FileManager: FileManagerHelper {
var fileCategory:FileCategory {
didSet {
didSetFileCategory()
}
}
required init(fileCategory:FileCategory,fileType:FileTypes = .Image) {
self.fileCategory = fileCategory
self.path = self.folderPath + self.fileName
didSetFileCategory()
}
private func didSetFileCategory() {
switch fileCategory {
case .XYZ:
print("Test")
//... other cases
}
}
}

Singleton class with instance variable and methods in Swift (iOS)

So, i am creating a Singleton class as below, and i need few instance variables in this class, such that any team member can access the instance variable and get the values. To do that, i will need to initialize these instance variables to a certain value at the beginning itself.
But i get a compilation error, saying "missing argument for parameter 'doesValueExists' in call".
What exactly i m doing wrong here ?
class ABC_Util {
private var doesValueExists: Bool
private var arrValues: NSMutableArray?
class var sharedInstance: ABC_Util {
struct ABC_UtilSingleton {
static let instance = ABC_Util()
}
return ABC_UtilSingleton.instance
}
init(doesValueExists: Bool, arrValues: NSMutableArray?) {
self.doesValueExists = self.checkValueExists()
self.arrValues = self.getArrayOfValues()
}
//method
internal func checkValueExists() -> Bool {
}
//method
internal func getArrayOfValues() -> NSMutableArray? {
}
}
Your initializer for ABC_Util is declared as:
init(doesValueExists:Bool, arrValues:NSMutableArray?) {
Therefore you cannot say
static let instance = ABC_Util()
The expression ABC_Util() would correspond to an initializer with no parameters, and you do not have such an initializer. You must say:
static let instance = ABC_Util(doesValueExists:someBool, arrValues:someArray)
(with appropriate values, of course).
You have to use your initializer in order to initialize your variables.
class ABC_Util {
private var doesValueExists:Bool
private var arrValues:NSMutableArray?
class var sharedInstance: ABC_Util
{
struct ABC_UtilSingleton
{
static let instance = ABC_Util(doesValueExists: true, arrValues: nil)
}
return ABC_UtilSingleton.instance
}
init(doesValueExists:Bool, arrValues:NSMutableArray?) {
self.doesValueExists = doesValueExists
self.arrValues = arrValues
}
//method
internal func checkValueExists()-> Bool
{
return true
}
//method
internal func getArrayOfValues()-> NSMutableArray?
{
return nil
}
}
And I recommend you to change your singleton declaration to the suggested syntax
static let sharedInstance: ABC_Util = ABC_Util(doesValueExists: true, arrValues: nil)
You could use as below.
class ABC_Util {
private var doesValueExists:Bool = false
private var arrValues:NSMutableArray?
class var sharedInstance: ABC_Util {
struct ABC_UtilSingleton {
static let instance = ABC_Util(doesValueExists: false, arrValues: ["a", "b", "c"])
}
return ABC_UtilSingleton.instance
}
init(doesValueExists:Bool, arrValues:NSMutableArray?) {
self.doesValueExists = self.checkValueExists()
self.arrValues = self.getArrayOfValues()
}
//method
internal func checkValueExists()-> Bool{
return self.doesValueExists
}
//method
internal func getArrayOfValues()-> NSMutableArray?{
return arrValues
}
}
i got the solution, when i tried this, worked fine!
class ABC_Util {
var doesValueExists:Bool = false
var arrValues:NSMutableArray? = nil
class var sharedInstance: ABC_Util
{
struct ABC_UtilSingleton
{
static let instance = ABC_Util()
}
return ABC_UtilSingleton.instance
}
init() {
self.doesValueExists = self.checkValueExists()
self.arrValues = self.getArrayOfValues()
}
//method
internal func checkValueExists()-> Bool
{
//return true/false
}
//method
internal func getArrayOfValues()-> NSMutableArray?
{
//return array/nil
}
}

RLMObject property NSDecimalNumber

I understand that RLMObjects cannot store NSDecimalNumber. To get around this, I tried the following, but failed:
private dynamic var _amount: String = ""
public var amount: NSDecimalNumber {
get { return NSDecimalNumber(string: _amount) }
set { _amount = newValue.stringValue }
}
I am getting a failure stating the RLMObjects cannot store NSDecimalNumbers. I was under the impression that non-dynamic properties would not be stored in Realm
Any property of RLMObjects must be dynamic. So amount: NSDecimalNumber property should be defined as dynamic
Like below:
private dynamic var _amount: String = ""
public dynamic var amount: NSDecimalNumber {
get { return NSDecimalNumber(string: _amount) }
set { _amount = newValue.stringValue }
}
And computed property should not be persisted. (Of course, amount property is NSDecimalNumber, so it can not be persisted in Realm. If amount property will be persisted, exception occured)
To prevent it, you can override ignoredProperties() method and return "amount" as string array.
override public class func ignoredProperties() -> [AnyObject]! {
return ["amount"]
}
Based on the above, complete class definition is as follows:
public class Product: RLMObject {
private dynamic var _amount: String = ""
public dynamic var amount: NSDecimalNumber {
get { return NSDecimalNumber(string: _amount) }
set { _amount = newValue.stringValue }
}
public override class func ignoredProperties() -> [String]! {
return ["amount"]
}
}

Resources