what is the type of shared? - arrays

what is the type of shared? what is the bracket at the end of the code use for?
Thanks!
class CallHistories: NSObject {
private var timer: Timer?
private var refreshUICallHistories = false
private var firebase: DatabaseReference?
static let shared: CallHistories = {
let instance = CallHistories()
return instance
} ()
}

No, shared is just an instance of CallHistories which is lazily initialized.

If you are asking whether 'shared' is an array? Then NO,
It's an instance of CallHistories
If you need to make it as array. Then
static let shared: [CallHistories] = {
let arrayInstance = [CallHistories]()
return arrayInstance
} ()
PS: (I Have not tested this code)

The type is CallHistories. It's a singleton, a single shared instance of the class which is persistent during the life cycle of the app.
The instance is created lazily that means it's created once on the first access of shared.
By the way your code is outdated. In Swift 3+ just write (without the closure).
static let shared = CallHistories()
And you are going to use it with
let sharedHistories = CallHistories.shared

Shared is an object of type CallHistories. There are brackets at the end, because variable shared is initialized with closure. You can initialize any variable in this way:
let myCustomView: UIView = {
let view = UIView()
return view
}()
More examples here:
Initialize closure in Swift

Related

Address of Array & Remove(at :) IOS

I'm passing an array of a specific model by reference between ViewControllers.
If I change any value of a specific element in the array it reflects well in all ViewControllers but when I remove an element from that array it doesn't reflect to the other controllers.
Does the remove(at: ) function create new array and refer to another address?
And if so how to delete an element without changing the address of array so it can reflect this change on the other view controllers?
Swift Arrays are value types (specifically, an array is a struct), not reference types, so you are mistaken when you say that you are "passing an array of a specific model by reference between view controllers". You can only ever pass a Swift array as a value.
Arrays, like other structs, have copy-on-modify semantics. As soon as you change the array itself a copy is made and the change is made to the copy.
Now, in your case the array contains references to model objects; When you update the model object you change the object itself, not the reference held in the array, so you see the change reflected in all of your view controllers.
An analogy might be the difference between adding a house to a street (which changes the street itself) versus changing the occupants of an existing house on the street.
I would suggest you implement a model object that provides abstraction from the underlying array so that you have better code and avoid the issue with array references.
One approach could be something like:
struct MyModel {
let name: String
let size: Int
}
class MyData {
private var _models = [MyModel]()
var models: [MyModel] {
return _models
}
func insert(model: MyModel) {
self._models.append(model)
}
func removeModel(at: Int) {
guard at >= 0 && at < _models.count else {
return
}
self._models.remove(at: at)
}
}
Although this isn't ideal as it still requires model consumers to know indices in the underlying array. I would prefer something like this:
struct MyModel: Hashable {
let name: String
let size: Int
}
class MyData {
private var _models = [MyModel]()
var models: [MyModel] {
return _models
}
func insert(model: MyModel) {
self._models.append(model)
}
func remove(model: MyModel) -> Bool {
if let index = self._models.index(of: model) {
_models.remove(at: index)
return true
} else {
return false
}
}
}
Now I don't need to know what internal collection MyData uses to store the models.
If you need to pass an array (or any other value type) by reference, you could go through an intermediate structure that manages the indirection for you.
[EDIT] changed to use KeyPaths available in Swift 4.
// Generic class to hold a "weak" reference to a property from an object
// including properties that are valued types such as arrays, structs, etc.
// This is merely an encapsulation of Swift's native KeyPath feature
// to make the code a bit more readable and simpler to use
//
class ReferenceTo<ValueType> { var value:ValueType! { get { return nil} set {} } }
class Reference<OwnerType:AnyObject,ValueType>:ReferenceTo<ValueType>
{
internal weak var owner:OwnerType!
internal var property:ReferenceWritableKeyPath<OwnerType,ValueType>! = nil
internal var valueRef:KeyPath<OwnerType,ValueType>! = nil
init(_ owner:OwnerType, _ property:ReferenceWritableKeyPath<OwnerType,ValueType>)
{ (self.owner,self.property) = (owner,property) }
init(_ owner:OwnerType, get valueRef:KeyPath<OwnerType,ValueType>)
{ (self.owner,self.valueRef) = (owner,valueRef) }
override var value:ValueType!
{
get { return valueRef != nil ? owner?[keyPath:valueRef] : owner?[keyPath:property] }
set { owner?[keyPath:property] = newValue }
}
}
With this generic class you can create references to valued type properties of object instances and manipulate them anywhere in your code as if the valued type property was a reference type.
// Example class with a read/write and a read-only property:
class MyObject
{
var myArray = [1,2,3,4]
var total:Int { return myArray.reduce(0,+) }
}
var instance:MyObject! = MyObject()
// create a reference to the array (valued type)
// that can be used anywhere and passed around as a parameter
let arrayRef = Reference(instance, \.myArray)
// the value is accessed and manipulated using the
// "value" property of the reference
arrayRef.value.remove(at:2)
arrayRef.value.append(5)
print(instance.myArray) // [1,2,4,5]
// Read-only properties can also be manipulated as
// references
let valueRef = Reference(instance, get:\.total)
print(valueRef.value) // 12
The Reference class allows passing the value as a reference to function parameters
// a function that expects a reference to an array
// would be declared as follows
func changeArray(_ array:ReferenceTo<[Int]>)
{ array.value.insert(9, at: 1) }
// the reference can also be used as an inout parameter
func shift(_ array:inout [Int])
{ array = Array(array.dropFirst()) + Array(array.prefix(1)) }
changeArray(arrayRef)
shift(&arrayRef.value!)
print(instance.myArray) // [9,2,4,5,1]
...
// the reference uses a weak link to the owner
// of the referenced property or value
// so there will be no strong reference cycle issues even
// if the reference is used in an object held strongly
// by the owner itself
instance = nil
print(arrayRef.value) // none ... no more value after the owner is gone

How do I pass an array of custom objects in Swift

I am trying to make a main menu for an Mac application as a beginning task to learn about Swift. Here is my code, which does not work.
In the AppDelegate
import Foundation
import Cocoa
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate
{
#IBOutlet weak var window: NSWindow!
//private let mainWindow = NSWindow(frame: NSWindow.mainScreen().bounds)
//let mainWindow = NSWindow()
//let statusItem = NSStatusBar.systemStatusBar().statusItemWithLength(NSSquareStatusItemLength)
func applicationDidFinishLaunching(aNotification: NSNotification)
{
// Insert code here to initialize your application
let menuData = [getMainMenuItems]
//[makeMainMenu, menuData]
}
}
And then in a different project file, named Swift_FileManager
import Foundation
import Cocoa
class menuArrayObject
{
var title: String = ""
var subMenuTitles: [String] = []
}
func getMainMenuItems (menuData:Array<AnyObject>) -> AnyObject
{
//Make a new menu array
var menuData = [AnyObject]()
let arrayObject1 = menuArrayObject()
arrayObject1.title = "Project"
arrayObject1.subMenuTitles = ["New Project","Open Project","Save Project", "Quit Project"]
menuData.append(arrayObject1)
return menuData
}
The code compiles but the function getMainMenuItems is never called.
Can somebody shed some light on the (probably very simple) issue here? Thanks in advance
let menuData = [getMainMenuItems]
This line (probably) isn't doing what you think it's doing. What it's doing is creating an array of [(Array<AnyObject>)->(AnyObject)] type (an array of functions that take an array of AnyObjects as input, and return an AnyObject) – and adding your getMainMenuItems function to it.
It's not calling your function at all.
In order to call a function, you need to use a pair of brackets (), containing the required input. In this case, your getMainMenuItems method expects an array of AnyObjects (although it never appears to actually use them).
For example:
let menuData = getMainMenuItems([/* Insert your objects here */])
Although that all being said, I'm not entirely sure that your getMainMenuItems function actually needs an input, as you never use it. I think you're looking for something like this:
func getMainMenuItems() -> [MenuArrayObject] {
// create an empty array of MenuArrayObjects
var menuData = [MenuArrayObject]()
let arrayObject1 = MenuArrayObject()
arrayObject1.title = "Project"
arrayObject1.subMenuTitles = ["New Project","Open Project","Save Project", "Quit Project"]
menuData.append(arrayObject1)
return menuData
}
Note that the function no longer has an input, and I've replaced AnyObject with [MenuArrayObject]. It's best to be as type specific as you can in Swift (and pretty much every other OOP language), so you should really steer away from AnyObject unless you have good reason to use it.
Now you can just invoke your function like this:
let menuData = getMainMenuItems()
and it will return an array of MenuArrayObjects.
If you're trying to make the function so that it'll add an object to an already existing array, then you can use an inout parameter in your function. This will let you pass an array into your function, which it can modify.
For example:
func getMainMenuItems(inout menuData:[MenuArrayObject]) {
let arrayObject1 = MenuArrayObject()
arrayObject1.title = "Project"
arrayObject1.subMenuTitles = ["New Project","Open Project","Save Project", "Quit Project"]
menuData.append(arrayObject1)
}
You can then call it like so:
// an existing array of MenuArrayObjects
var menuDataArray = [MenuArrayObject]()
// call function with array – which it will append an element to
getMainMenuItems(&menuDataArray)
The code let menuData = [getMainMenuItems] is just creating an array containing the function. I'm guessing that you mean to call the function instead. That looks something like:
let menuData = getMainMenuItems([])
In applicationDidFinishLaunching you need to instantiate menuArrayObject:
let myMenuArray = menuArrayObject()
And then call it:
let menuData = myMenuArray.getMainMenuItems()
Your getMainMenuItems method, it seems looking at what you wrote in the method, should be defined as:
func getMainMenuItems() -> [AnyObject]

Having array problems in Swift

I am learning how to build apps and working with Swift for this project.
I had a buddy help me pull data in from a website and it looks like he created classes with variables and mapped them to certain extensions (IE "Username") so when I call the variable data such as profile I would call it. The below uses luck_30 able to store "Stats.luck_30"
luck_30.text = profile.luck_30
So inside one of my variables that is in this "Profile" class is setup into an array. I can pull the array out of the class, but I can't seem to do for while statement replacing the [#] with a variable from the for command.
func aliveWorkers(profile: Profile) -> NSNumber{
var myworkers : Array = profile.workers!
//this test works and returns the proper value
var testworker: NSNumber = myworkers[0].alive!
println("The satus of the test worker is " + testworker.description)
/* This code is giving error "Could not find member alive" it does not ifor var
for ifor in myworkers{
var thisworker: NSNumber = myworkers[ifor].alive! as NSNumber
}
*/
return 42
}
Your variable ifor is not a counter, it is an actual object. You could do something like this:
for worker in myWorkers {
let workerIsAlive = worker.alive!
}
Alternatively, if you need the index,
for i in 0 ..< myWorkers.count {
let worker = myWorkers[i]
let workerIsAlive = worker.alive!
}
If you need both:
for (i, worker) in enumerate(myWorkers) {
let workerIsAlive = worker.alive!
}
And as a matter of style, I would stay away from NSNumber and use Int or Bool or whatever the data actually is. Also, it looks like the alive variable should not be optional, as you're unwrapping it everywhere. To avoid "mysterious" crashes later, you may want to think about making it a non-optional type.
when using a for in loop, your loop variable isn't an index, its the objects you're looping through. so..
func aliveWorkers() {
var myworkers = [1, 2, 3]
//this test works and returns the proper value
let testworker = myworkers[0]
print("The satus of the test worker is \(testworker)")
for ifor in myworkers {
print(ifor)
}
}
Notice a few things... you don't need to use + to concatenate those strings. you can just use string interpolation. \(variable) inserts the value of variable in the string.
Try to use let instead of var when you don't change the variable. You don't need to explicitly define type on variables either.

Using functions in arrays Swift

i use the following function to retrieve a random person from an array:
func getRandomPerson() -> String{
if(personArray.isEmpty){
return ""
} else {
var tempArray: [String] = []
for person in personArray{
tempArray += [person.getName()]
}
var unsignedArrayCount = UInt32(tempArray.count)
var unsignedRandomNumber = arc4random_uniform(unsignedArrayCount)
var randomNumber = Int(unsignedRandomNumber)
if tempArray.isEmpty {
return ""
} else {
return tempArray[randomNumber]
}
}
}
I would like to use this function inside an array of strings, Like this:
var theDares: [String] = ["Dare1 \(getRandomPerson())", "Dare2", "Dare3", "Dare4", "Dare5"]
But when i use the functions, it only runs the function once. Can you make the function run everytime you use the "Dare1" in this instance.
Thanks in advance
I think you are asking if you can set up your array so every time you fetch the object at index 0, it re-builds the value there.
The short answer is no. Your code is creating an array of strings, and the item at index 0 is built ONCE using a function call.
However, it is possible to make a custom class implement the subscript operator. You could create a custom object that looks like an array and allows you to index into it using an Int index. In response to the index operator you could run custom code that built and returned a random string.
Since it sounds like you're a beginning programmer creating a custom class the implements the subscript operator might be beyond your current abilities however.
Try like this:
let personArray = ["John", "Steve", "Tim"]
var randomPerson: String {
return personArray.isEmpty ? "" : personArray[Int(arc4random_uniform(UInt32(personArray.count)))]
}
println(randomPerson) // "Steve"

Initializing reference types outside of a function in Actionscript 2

I have this small class called City that simply holds some information about a city, here it is:
class com.weatherwidget.City {
var zipCode:String;
var forecastText:Array = new Array(5);
}
When I have an array of cities and I change one of the forecastText of one city it will change that forecastText for all of the cities.
For example:
import com.weatherwidget.City;
var arr:Array = new Array();
arr.push(new City());
arr.push(new City());
arr[0].forecastText[0] = "Cloudy";
trace(arr[0].forecastText[0]);
trace(arr[1].forecastText[0]);
Will have the following output:
Cloudy
Cloudy
Even though I only changed arr[0].forecastText[0]. I think I must be misunderstanding something about arrays in objects for actionscript 2.
well the reason why ... hmmm ... little complicated to explain ...
alright ... ActionScript is prototype-oriented, as is ECMA-script ... classes are only a syntactic sugar introduced by actionscript 2 (this has changed yet again in as3, but that's a different subject) ...
so if this is the original code:
class com.weatherwidget.City {
var zipCode:String;
var forecastText:Array = new Array(5);
}
then this is, what actually happens:
//all classes get stuffed into _global, with packages being a property path:
if (_global.com == undefined) _global.com = {};
if (_global.com.weatherwidget == undefined) _global.com.weatherwidget = {};
//and the actual definition:
_global.com.weatherwidget.City = function () {};
_global.com.weatherwidget.City.prototype = { forecastText:new Array(5) }
the prototype object of City, that serves as prototype for instances of City, has a property called forecastText, which is an Array of length 5 ... so when looking up forecastText on an instance of City, it cannot be found directly and will be looked up in the prototype chain ... it will be found in the instance's prototype ... thus, all instances share the same Array ...
the difference is, that the second example gets translated to:
//same thing here:
if (_global.com == undefined) _global.com = {};
if (_global.com.weatherwidget == undefined) _global.com.weatherwidget = {};
//and the actual definition this time:
_global.com.weatherwidget.City = function () { this.forecastText = new Array(5); };
_global.com.weatherwidget.City.prototype = {}
as you might have noticed, declared members are only a compiletime thing ... if nothing is assigned to them, they simply will not exist at runtime ...
well, this explenation requires, that you either know JavaScript or ActionScript 1 a little, but i hope it helps ...
greetz
back2dos
The array needs to be initialized inside of a constructor for some reason or all the City objects will point to the same array. So the city class should look like:
class com.weatherwidget.City {
var zipCode:String;
var forecastIcons:Array;
function City() {
forecastIcons = new Array(5);
}
}
I still don't know why it must be initialized in a constructor since the array isn't static, so if anyone would like to explain this that would be much appreciated.

Resources