I'm one month into self-learning Swift, and I would like some advice to improve my coding skills.
I have listed 2 situations that I think I need to improve. I'd like some feedback focusing on my use of static
variables for changing data between ViewControllers
and subviews
.
1.0 Image 1 shows the app flow (Left = HomeController
), middle = MenuController
, Right = FavouritesController
)
In HomeController
there is a UIView
subview. From this subview the current quote (HomeController.homeControllerCurrentQuote
) displayed can be saved to favourites
array. This is a static array defined in FavouritesController
.
The functions below are called from the subview
within HomeController
. I made HomeController.homeControllerCurrentQuote
static because the subview needs access to it. Likewise for FavouritesController.favourites
.
In FavouritesController
the data contained in FavouritesController.favourites
array is used to populate a tableVIew
.
// FavouritesController.favourites is static variable!
// HomeController.homeControllerCurrentQuote is static variable! updated as user scrolls
func handleFavourite() {
let favourites = FavouritesController.favourites
if favourites.contains(HomeController.homeControllerCurrentQuote) {
removeFromFavourites()
} else { FavouritesController.favourites.append(HomeController.homeControllerCurrentQuote)
UserDefaults.standard.set(try? PropertyListEncoder().encode(FavouritesController.favourites), forKey:"myKey")
}
}
func removeFromFavourites() {
var tempArray: [Quote] = [.init(category: "", quote: "", author: "")]
tempArray = FavouritesController.favourites
let searchString = HomeController.homeControllerCurrentQuote.quote
var filteredArray = [Quote]()
filteredArray = tempArray.filter( { !$0.quote.contains(searchString) } )
UserDefaults.standard.set(try? PropertyListEncoder().encode(filteredArray), forKey:"myKey")
}
// update static variable on HomeController
internal override func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
....
HomeController.homeControllerCurrentQuote = Quote(category: cell.categoryLabel.text ?? "", quote: cell.quoteLabel.text ?? "", author: author)
....
}
Should I change how this is done? I don't like the use of static variables but as it's my first app I was more focused on getting it done rather than how it was done. Is it a good case for using a delegate
and protocol
to communicate between the views (I've never used this before)? If so how would I start to think about implementing it or, as it works, is what I've done satisfactory?
2.0 When the app launches on HomeController
required data is generated and is stored in a static variable.
// [category : [quote : author]]
static var xQuotesByCategory: [String : [String : String]] = [:]
I make this data static because when I instantiate HomeController
again from another controller, I don't want to have to refetch the data. I want to retrieve it once. Then when a new instance of HomeController
is called I can make this check which should return false. Is this an appropriate use of a static variable?
if HomeController.xQuotesByCategory.values.isEmpty {
... fetchJson()
}
Following on from this, as HomeController.xQuotesByCategory
is static, on CategoriesController
I can call
var categories = Array(HomeController.xQuotesByCategory.keys)
This gets only the outer keys
(categories) which I use to create the collectionView
cells
with the text and images shown in image 2. Again, same question, is this appropriate use of a static variable? Is there better way to ensure data is loaded only once and then pass the keys
to CategoriesController
in a different way when it's required?
If you'd like to try running the app, there is a test version available on TestFlight. Let me know and I can add you in TestFlight!