asma22 asma22 - 6 months ago 11
Objective-C Question

Shouldn't every .swift file be a class?

I have some experience in ObjC and I just started learning Swift. In Objc everything is a class through

@interface
in
.h
and
@implementation
of
.m
, or in other Swift classes that I have seen everything is usually in some form of

class MyCustomClassInhertingfrom: SomeFoundationClass { //methods & properties}


Yet here in some class named
pancakeHouse.Swift
there is no mention of the keyword
class
WHY? Isn't this a Model Class? Doesn't this break the MVC design pattern? Is this happening because of new powerful features of enums& structs vs class in Swift?_____I am confused obviously!

import UIKit
import CoreLocation

enum PriceGuide : Int {
case Unknown = 0
case Low = 1
case Medium = 2
case High = 3
}

extension PriceGuide : CustomStringConvertible {
var description : String {
switch self {
case .Unknown:
return "?"
case .Low:
return "$"
case .Medium:
return "$$"
case .High:
return "$$$"
}
}
}

enum PancakeRating {
case Unknown
case Rating(Int)
}

extension PancakeRating {
init?(value: Int) {
if value > 0 && value <= 5 {
self = .Rating(value)
} else {
self = .Unknown
}
}
}

extension PancakeRating {
var ratingImage : UIImage? {
guard let baseName = ratingImageName else {
return nil
}
return UIImage(named: baseName)
}

var smallRatingImage : UIImage? {
guard let baseName = ratingImageName else {
return nil
}
return UIImage(named: "\(baseName)_small")
}

private var ratingImageName : String? {
switch self {
case .Unknown:
return nil
case .Rating(let value):
return "pancake_rate_\(value)"
}
}
}



struct PancakeHouse {
let name: String
let photo: UIImage?
let thumbnail: UIImage?
let priceGuide: PriceGuide
let location: CLLocationCoordinate2D?
let details: String
let rating: PancakeRating
}

extension PancakeHouse {
init?(dict: [String : AnyObject]) {
guard let name = dict["name"] as? String,
let priceGuideRaw = dict["priceGuide"] as? Int,
let priceGuide = PriceGuide(rawValue: priceGuideRaw),
let details = dict["details"] as? String,
let ratingRaw = dict["rating"] as? Int,
let rating = PancakeRating(value: ratingRaw) else {
return nil
}

self.name = name
self.priceGuide = priceGuide
self.details = details
self.rating = rating

if let imageName = dict["imageName"] as? String where !imageName.isEmpty {
photo = UIImage(named: imageName)
} else {
photo = nil
}

if let thumbnailName = dict["thumbnailName"] as? String where !thumbnailName.isEmpty {
thumbnail = UIImage(named: thumbnailName)
} else {
thumbnail = nil
}

if let latitude = dict["latitude"] as? Double,
let longitude = dict["longitude"] as? Double {
location = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
} else {
location = nil
}
}
}

extension PancakeHouse {
static func loadDefaultPancakeHouses() -> [PancakeHouse]? {
return self.loadPancakeHousesFromPlistNamed("pancake_houses")
}

static func loadPancakeHousesFromPlistNamed(plistName: String) -> [PancakeHouse]? {
guard let path = NSBundle.mainBundle().pathForResource(plistName, ofType: "plist"),
let array = NSArray(contentsOfFile: path) as? [[String : AnyObject]] else {
return nil
}

return array.map { PancakeHouse(dict: $0) }
.filter { $0 != nil }
.map { $0! }
}
}

extension PancakeHouse : CustomStringConvertible {
var description : String {
return "\(name) :: \(details)"
}
}

extension PancakeHouse: Equatable {
}

func ==(lhs: PancakeHouse, rhs: PancakeHouse) -> Bool {
return lhs.name == rhs.name
}


Note: I would like an answer that also includes comparison of the
.swift
vs
.h
+
.m
; don't just consider this as a specific question, consider it as a general question, kindly explain or link the prerequisites's details needed to understand this question)

Answer

pancakeHouse.swift defines PancakeHouse and all the various things that go with it. That is perfectly good Swift style. There is no class here because PancakeHouse happens to be a struct, which is also perfectly good Swift style (and mildly preferred). Structs are much like classes in Swift, in that they can have data and methods (and extensions).

ObjC does not require that each class be defined in its own .h/.m pair, but it is fairly typical ObjC style to do so. That said, even in ObjC there are exceptions. It is common to have mutable subclasses defined in the same file as their base class (NSArray and NSMutableArray are both defined in NSArray.h). Swift style has evolved towards lumping related things together more closely. One style makes it easier to find something if you know its name. The other makes it easier to find related concepts together. Both have their advantages, and once people are used to one they tend to believe that that one is obviously correct. But they're just different ways of organizing.

Note that this file also makes use of Swift extensions to break up related methods. That is also common and good Swift. Old ObjC did that with categories, but it's much less common to organize ObjC code that way today (categories are used for other things now). Again, neither is deeply correct. It's just the styles that have evolved.

Comments