Crash in Swift code due to access of deallocated references - ios

I've created the following classes:
class Person {
private var name: String = ""
private init(name thisName: String) {
name = thisName
}
class func CreatePerson(#type: String, name: String) -> Person! {
if type == "girl" {
return Female(name: name)
}
else if type == "boy" {
return Male(name: name)
}
return nil
}
func PrintName() {
println(name)
}
}
class Male: Person {
override init(name thisName: String) {
super.init(name: thisName)
}
deinit {
println("Deleting a male.")
}
}
class Female: Person {
deinit {
println("Deleting a female.")
}
}
class AnotherClass {
var secondPeopleArray: [Person]! = nil
func DoSomething(#people: [Person]) {
secondPeopleArray = [Person]()
for person: Person! in people {
let male: Male! = person as? Male
if male != nil {
secondPeopleArray.append(male)
}
}
}
}
As you can see, I've created a class called Person with two subclasses (Male and Female). I've also created a class (AnotherClass) that takes an array of Person classes and builds a new array of Male classes. As you can see, the
I've created the following code that builds the Person class arrays and calls the Another class function DoSomething. DoSomething allocates the array and filters the people array and appends only the Male classes to the secondPeopleArray member.
var firstPeopleArray = [Person]()
var firstPerson: Person = Person.CreatePerson(type: "boy", name: "Bill")
var secondPerson: Person = Person.CreatePerson(type: "boy", name: "Ted")
var thirdPerson: Person = Person.CreatePerson(type: "girl", name: "Nancy")
var fourthPerson: Person = Person.CreatePerson(type: "girl", name: "Diane")
firstPeopleArray.append(firstPerson)
firstPeopleArray.append(secondPerson)
firstPeopleArray.append(thirdPerson)
firstPeopleArray.append(fourthPerson)
var anotherClass: AnotherClass = AnotherClass()
anotherClass.DoSomething(people: firstPeopleArray)
anotherClass.DoSomething(people: firstPeopleArray)
for person in firstPeopleArray {
person.PrintName()
}
As you can see, the DoSomething function is called twice. This is intentional. The first time DoSomething is called, the array in the AnotherClass is created properly. The second time the DoSomething function is called, a new array is allocated (which deallocates the old array). The strange thing is the members of the array are also deallocated, which results in firstPeopleArray to have deallocated references as members of the array. Accessing the member in the for loop results in a crash.
I've found the following line is the culprit:
for person: Person! in people {
Changing this line to the following fixes the issue:
for person: Person in people {
The question is, Why? Why would the unwrapping symbol (the !) affect the references in a way in which having the symbol there results in the system thinking it needs to deallocate the member of the array when the array is deallocated and the reference clearly is used in the firstPeopleArray?

Related

Typecasting to Generic class in Swift

Im trying to typecast an object to a class that uses Generics. Here is some code for better understanding
I've a protocol named wheel
protocol Wheel
I've a class named Wings
class Wings {
var count = 2
}
Now, I have a generic class named VehicleWrapper
class VehicleWrapper<T: Wings&Wheel> {
var vehicle: T
}
Now finally I have an object which I would want to typecast to VehicleWrapper and use the count property from Wings class but I dont know the type T would be while typecasting this. Is there a way to typecast this and use the count variable?
One problem with your question is that your code is illegal. You can't just say protocol Wheel like that; you need curly braces (which may or may not contains the protocol's requirements). And your VehicleWrapper has no initializer, so the compiler will never allow it.
But let's suppose we've taken care of all that. My guess, then, is that the problem you're having is that it is not permitted to cast to a generic. For example, you cannot cast to a VehicleWrapper. This is because a generic is not a type. The type is the resolved generic.
To illustrate:
protocol Wheel {}
class Wings {
var count = 2
}
class VehicleWrapper<T: Wings & Wheel> {
var vehicle: T
init(vehicle: T) { self.vehicle = vehicle }
}
class Thing: Wings, Wheel {}
let thing = Thing()
class What<T: Wings & Wheel>: VehicleWrapper<T> {}
let what = What(vehicle: thing)
if let what = what as? VehicleWrapper { // compile error
print(what.vehicle.count)
}
As you can see, our attempt cast to a VehicleWrapper is met with scorn from the compiler. We could legally, however, try casting to a VehicleWrapper<Thing>.
The real issue for your question is that it is difficult to imagine a use case where it make sense to need to do that, since how could this object come into existence in the first place without your knowing what it is?
It isn't clear what you are trying to achieve, but I don't think that generics are the way to achieve it.
Generics essentially allow you to define operations on types, independent of what those types are. This is different to inheritance or protocols that allow you define the operations that can be performed on a particular type.
Most importantly, different generic object types are not co-variant; There is no functional relationship between GenericClass<SuperClass> and GenericClass<SubclassOfSuperClass> even though the generic types do have a inheritance relationship.
Taking your example, you are probably better off using some protocols.
Consider
protocol Wheeled {
var numberOfWheels: Int { get }
}
protocol Movable {
func moveForward()
func stop()
}
Now, we can define a Vehicle class and some subclasses in terms of those protocols:
class Vehicle: Movable {
var name: String
var seatingCapacity: Int
init(name: String, seatingCapacity: Int) {
self.name = name
self.seatingCapacity = seatingCapacity
}
func moveForward() {}
func stop() {}
}
class Car: Vehicle, Wheeled {
var numberOfWheels: Int
init(name: String) {
self.numberOfWheels = 4
super.init(name: name, seatingCapacity: 5)
}
}
class Truck: Vehicle, Wheeled {
var numberOfWheels: Int
init(name: String) {
self.numberOfWheels = 18
super.init(name: name, seatingCapacity: 2)
}
}
Now, let's define a light aircraft:
protocol Winged {
var numberOfWings: Int { get }
func takeOff()
func land()
}
class LightAirplane: Vehicle, Wheeled, Winged {
var numberOfWheels: Int
var numberOfWings: Int
init(name: String) {
self.numberOfWheels = 3
self.numberOfWings = 2
super.init(name: name, seatingCapacity: 4)
}
func takeOff() {}
func land() {}
}
Using these definitions we can take an Vehicle (whether it is a car, truck or plane) and ask it to moveForward() or stop().
We can take an object that conforms to Winged and ask it to takeOff() and land().
Where could you use generics? Let's look at our Truck - We can make that a generic class:
class CargoTruck<Cargo>: Truck {
private (set) var cargo: Cargo?
init(name: String, cargo: Cargo? = nil) {
self.cargo = cargo
super.init(name: name)
}
func load(cargo: Cargo) {
self.cargo = cargo
}
func unload() {
self.cargo = nil
}
}
Now we have a subclass of Truck that can load and unload some sort of Cargo but our implementation doesn't need to care what it is:
struct Cattle {}
struct Appliance {}
var cattleTruck = CargoTruck(name:"Cattle Truck", cargo:[Cattle]())
var applianceTruck = CargoTruck(name:"Container Truck", cargo: Appliance()))
We have cattleTruck which is a CargoTruck<[Cattle]? - i.e. it can hold an array of Cattle and applianceTruck which is a CargoTruck<Appliance> - It can hold a single Appliance
What if we wanted to limit the type of the cargo - We can add a constraint to the generic type:
protocol ShippingContainer {
}
struct StandardContainer: ShippingContainer {
}
struct RefrigeratedContainer: ShippingContainer {
}
class ContainerTruck<Cargo: ShippingContainer>: CargoTruck<Cargo> {
}
let refer = ContainerTruck(name: "ReferTruck", cargo: RefrigeratedContainer())
refer.unload()
let bad = ContainerTruck(name:"Error", cargo: 12) // Error an Int is not a container
The generic doesn't define what the truck can do (move, load, unload etc), but rather what it does it to - It can load a ShippingContainer

Swift setting object's properties to nil

I am new to Swift and I'm facing a problem.
My problem is quite simple:
I have a simple class with some object in it (declared in their own file) :
class Outcome : NSObject {
var foo : SomeClass?
var doo : OtherClass?
var roo: AnotherClass?
}
What I want to do is when an object of the class is set, set all the other object to nil, so I used the didSet feature and add a resetData method that is supposed to set all the object to nil, except the one I just set.
The class looks like this :
class Outcome : NSObject {
var foo : SomeClass? {
didSet { self.resetData(exeption: foo!) }
var doo : OtherClass? {
didSet { self.resetData(exeption: doo!) }
}
var roo: AnotherClass? {
didSet { self.resetData(exeption: roo!) }
}
func resetData (exeption: AnyObject) {
var allObjects = NSArray(array: [self.foo ?? NSNull(), self.doo ?? NSNull(), self.roo ?? NSNull()])
for var anObject in (allObjects as NSArray as! [NSObject?]) {
if exeption.isEqual(anObject) == false {
anObject = nil
}
}
}
}
The idea of the resetData method is to set all the objects to nil except the exception (which is the object I just set in my view controller)
The code is working and the instruction anObject = nil is executed, but the problem is that when I set a set a beakpoint I can clearly see that the object is not nil, so this does not do what I want.
I think it is a question of reference, I do not really get it, is it possible to set an object to nil ? Is there a better way to do this ?
As mentioned in the comments, your loop does not modify the class
properties at all, only the anObject loop variable.
If the intention is to define a type which holds either an instance
of SomeClass or an instance of OtherClass or an instance
of AnotherClass then an enum would be a better choice:
enum Outcome {
case foo(SomeClass)
case doo(OtherClass)
case roo(AnotherClass)
}
Usage example:
var outCome = Outcome.foo(SomeClass())
print(outCome) // foo(<SomeClass: 0x1009000b0>)
// ...
outCome = .doo(OtherClass())
print(outCome) // doo(<OtherClass: 0x100d00540>)

Appending Model into array in Swift

So I have created a model class where I am using Alamofire to get data from an API. I want to display that data in the table to view so I was thinking of appending that model into an array in the VC and call it in the custom cell.
But I want to append that model into the array only if a key value matches a particular string.
However when I am using a simple if statement in the VC its giving me a fatal error saying bad instruction.
Code
Calling the Model
var notificationModel: NotificationModel!
var notification = [NotificationModel]()
viewDidLoad
if notificationModel.type == "meeting" {
self.notification.append(notificationModel)
}
Model
Class NotificationModel
var _type: String!
var type: String {
if _type == nil {
_type = "Err"
}
return _type
}
func downloadData() {
...
}
}
Here you have force unwrap NotificationModel. And you are trying to access type of a nil value.
Please try with the following fix.
var notificationModel: NotificationModel!
var notification = [NotificationModel]()
if notificationModel?.type == "meeting" {
notification.append(notificationModel!)
}
Hope this resolves the issue.

How can I allow my function to accepts two different objects in swift?

I have a function which takes one argument. I wanted my function to accept two object types. How can I do it? Here is the example below:
func accept(user: Customer) {
...
}
It should accept Customer and Employee object reference.
accept(objRefCustomer)
accept(objRefEmployee)
Please help me in this case.
Alternative to super-classing: use protocols
You needn't necessarily use a superclass for this case (if Customer and Employee are struct value types; superclass option is not possible), but can rather use the more generic approach of protocols.
Define a protocol Users which blueprints properties and methods for your Customer and Employee instances (if we let Customer and Employee conform to Users, then we promise that instances of these two structures will have accessible the blueprinted properties and methods):
protocol Users {
var name: String { get }
func printTypeOfUser()
}
Define the Customer and Employee structures, and their conformance to the protocol Users:
struct Customer : Users {
let name: String
init(name: String) { self.name = name }
func printTypeOfUser() {
print("Is a Customer!")
}
}
struct Employee : Users {
let name: String
let id: Int
init(name: String, id: Int) { self.name = name; self.id = id }
func printTypeOfUser() {
print("Is an Employee!")
}
}
Now you can define a generic function where its generic, say T, is type constrained to types conforming to the protocol Users, which in this case is equivalent to the Customer or Employee types
func accept<T: Users>(user: T) {
print("Name of user: \(user.name) [\(user.dynamicType)]")
user.printTypeOfUser()
// do something additional employee-specific if user is an employee?
if let employee = user as? Employee {
print("User is an employee with id: \(employee.id)")
}
}
Example usage of this function for Employee as well as Customer instances:
let employee = Employee(name: "John", id: 1)
let customer = Customer(name: "Sarah")
accept(employee) /* Name of user: John [Employee]
Is an Employee!
User is an employee with id: 1 */
accept(customer) /* Name of user: Sarah [Customer]
Is a Customer! */
Instead of changing your Class structure and code base, you can use AnyObject. It will also be easier for you if, for example, in future you have to make this function accept parameters of class WaterMelon. Making all these classes inherit from a common parent class would be unnecessary overhead, not to mention hectic.
AnyObject is swift equivalent of objective c id. AnyObject is a protocol that can represent an instance of any class type.
It also has a more general counterpart, Any, which can represent any type at all (including structs and enums).
Following code will accept any class type parameter you pass:
func accept(sender : AnyObject) { //Or AnyObject? if you want to handle nil as well
...
}
To access properties of the classes you pass as AnyObject, you can use type casting.
For example below code will check sender type and typecast it for you:
if let customerRef = sender as? Customer {
// ...
// Sender is of customer class type. Use it with customerRef that we created
let customerName = customerRef.dynamicType.sampleNameProperty //Access a property of class Customer
customerRef.funcOfCustomerClass() //Call a method of class Customer
}
else{
//Sender is not of customer class type.
//Then it must be Employee??? Handle cases for employee here.
}
create a protocol, and use it as argument type. protocol can be also empty, it will work anyway. Works with struct and class as well;
ex:
protocol SomeFakeProtocol {}
class SomeClass: SomeFakeProtocol { //code here }
struct SomeStruct: SomeFakeProtocol { //code here }
func someFunction(arg: SomeFakeProtocol) { //code here }
Benefits - you can allow to use only types you want to. And, sure, you can do things like this:
extension String: SomeFakeProtocol {}
You can create a super class called People of Cutomer and Employee.
Then set user as type of People:
func accept(user: People) {
...
}
You don't need a super class, you can just pass an object of type AnyObject and in your function check the type of the object passed:
func accept(user: AnyObject) {
if let usr = user as? Person {
...
}
}
But if you have many types you want to pass you may want to make a protocol or a super class.

property underscore instance and getter in object-c and their equivalent in swift

I ran into a problem when I was trying to "translate" some Objective-C code to Swift. I define Garage and Car in CoreData. Garage has a relationship to Car called cars. I have a masterviewcontroller to display "Garage" class and detailviewcontroller to display a NSArray of "car" class. Here is my code in Objective-C. I want to let cars = allobjects when it is nil; otherwise just return it.
#property (nonatomic, strong) NSArray* cars;
- (NSArray*) cars {
if (_cars == nil) {
_cars = self.garage.cars.allObjects;
}
return _cars;
}
However, in Swift, it does not have a underscore instance for property, and I cannot let cars == nil since "==" cannot be applied to operands of type [Car]. I tried to use the following code, but it gave me two errors: "attempting to access 'cars' within its own getter" and "cannot assign a value of type '[AnyObject]?' to a value of type '[Car]'"
var garage : Garage?
var cars : [Car] {
if let a = cars {
get {
cars = self.garage?.cars.allObjects
}
}
Any help is appreciated.
UPDATE/////////////////////////////////////////////
Here is the method I used to solve my problem.
private var _cars: [Car]?
var cars: [Car]?
{
get {
if _cars == nil {
_cars = self.garage?.cars.allObjects as? [Car]
}
return _cars
}
set {
_cars = cars
}
}
Thank you for all the help.
I might suggest just having a computed property:
var cars : [Car]? {
return garage?.cars.allObjects
}
And, remember to make cars variable and optional array.
Looks like you need a lazy property:
lazy var cars: [Car]? = self.garage?.cars.allObjects
Yes, you need a lazy var.
Your code will be (Swift 2.3):
lazy var cars: [Car]? = { [unowned self] in
return self.garage?.cars.allObjects
}()
The trick are the { and the [unowned self]
Lazy var in sintax instance the value just one time and keep it, maybe it's what you want.
Maybe you just need a wrapper to get each time the value of self.garage?.cars.allObjects in which case you need a computed var, not a lazy var with a static value
var cars: [Car]? {
get {
return self.garage?.cars.allObjects
}
}
In Swift, you would generally replace properties with variables (var); if a property can be set in you init method and stays unchanged after that, you would use (let).
In your case, you have your own "get" method. In Swift, when you have a getter or setter method, there is no backing variable. So what you do, you create one. Typically as a private variable with a leading underscore.
You should think about how you reset the variable to nil. Having a setter is not a good idea, because you only want to allow setting the variable to nil and nothing else. If it is only set to nil inside the class itself, you can set the variable with underscore to nil. Otherwise you might add a function like "resetCars".
And note that if you have a "get" method, but none of "set", "willSet" and "didSet", you can just write the set code without any getter. So a typical usage would be:
private var _cars: [Car]?
func resetCars () -> Void { _cars = nil } // To allow resetting outside the class
var cars: [Car] {
if _cars == nil {
_cars = cleverlyCalculatedNonNilValue()
}
return _cars
}

Resources