Please feel free to suggest changes by raising a Pull Request on this document, or opening an Issue!
Today we're going to create our very own news viewing app! 🎉 Don't worry, we'll be guided through each step, and we've pre-written some of the more complicated code so we can get our app up and running in just one session.
Let's get to it! 🔨
-
Update the following fields:
- Product name: Something like 'bestest-news-reader'
- Team Leave this set to 'none'
- Organization Name: Something like
Codebar
- Organization Identifier: Something like
com.codebar
- Language: Swift :awesome:
- Use Core Data: Leave this unchecked
- Include Unit Tests: Uncheck this
- Include UI Tests: Uncheck this <img src=/3.png" title="Fill in the fields according to instructions" alt="alt text">
-
Run the project by hitting the
Play
button up top -
Another application will start - the
Simulator
. This application lets us see how our iOS app looks without needing a physical device. Given that we haven't made any changes, we should see an empty white screen. Amazing - we're now iOS developers!! ❤️ -
Now, open up the file
Main.storyboard
. This is the file where we represent the layout of our app. It's a great tool to use because it lets us easily visualise our app. -
A label is used to display non-interactive text. That is, our users can't change the text in this label, but we can. 👍 Create a label in the
Main.storyboard
file and write the word Codebar inside. -
Now run the app again by hitting the play button. We can see our label on the Simulator. We're now mid-level iOS Developers!! ⭐
-
Next we're going to add some dynamic data to our app. This is typically done by connecting to an API so we can get real time data from the Internet. We'll come back to this network code in a later workshop, but for now_....here's one we prepared earlier!_ Download this file:
-
Drag the downloaded file
NewsFetching.swift
into the Project Navigator section of your app -
This file contains 2 objects:
- NewsFetcher: A class for fetching news articles from newsapi.org
- NewsItem: A struct for holding the fetched news article data
-
In order to update our label, we have to add it to our
ViewController.swift
:class ViewController: UIViewController { @IBOutlet var content: UILabel! ...
-
Next, since we've included
NewsFetching.swift
in our project, we can now use theNewsFetcher
to fetch actual data. Add this code to theviewDidLoad()
method ofViewController.swift
:override func viewDidLoad() { super.viewDidLoad() // Create a new instance of NewsFetcher to do our fetching let fetcher = NewsFetcher() // Ask fetcher to get latest articles // This is an asynchronous call // Code between { ... } will be executed when the data has been fetched // Note: Result is a Swift type that captures either success or failure in a single enum fetcher.getLatestArticles { [weak self] (result: Result<[NewsItem], NewsFetcherError>) in switch result { case .success(let articles): // If fetching was successful, update content to show first title self?.content.text = articles.first?.title case .failure(let error): // If fetching failed, update content to show the error self?.content.text = "\(error)" } } }
-
Now run the app again by hitting the play button. We will need to wait while data is fetched from the server, but then we should see our label updated to show current content. Did it work??
-
Whoops - we forget to connect our label between our source file (
ViewController.swift
) and our storyboard (Main.storyboard
). Carefully follow the steps here to open the assistant editor and connect the label from the storyboard to the label in code. -
Run the app again by hitting the play button. We will need to wait while data is fetched, but then we should see
content
label being updated to show a real title. Oops, the text is getting cropped! -
We need to add some constraints to make the label size larger.
-
Run the app again by hitting the play button. We will need to wait while data is fetched, but then we should see
content
label being updated to show a real title. Woohoo!! We're now senior iOS Developers!! 🏆
-
Showing a single title is a bit dull. Let's make this app truly great and show a whole scrolling table of titles!! To do this we need a
UITableView
rather than aUILabel
. AUITableView
is what we see a lot in iOS apps. It's a scrolling list of repetitive information. In our case, we will show a scrolling list ofNewsItems
. -
Open
Main.storyboard
and delete the content label you created earlier. Now drag in a UITableView. -
Now we need to change the label declaration to a
UITableView
declaration:class ViewController: UIViewController { @IBOutlet var tableView: UITableView! ...
-
Don't forget to connect the outlet on the
UITableView
in the Storyboard. -
A
UITableView
needs aUITableViewDataSource
to tell it what information to show. At minimum, aUITableViewDataSource
provides this information:- numberOfSections: How many sections the table contains (a section is a group of items)
- numberOfRowsInSection: How many rows the table contains (a row for each
NewsItem
) - cellForRow: A visual representation of the
NewsItems
-
Update
ViewController
so it is able to act as aUITableViewDataSource
inViewController.swift
:class ViewController: UIViewController { @IBOutlet var tableView: UITableView! var articles = [NewsItem]() override func viewDidLoad() { super.viewDidLoad() // Configure the TableView to reuse cells based on an identifier tableView.register(UITableViewCell.self, forCellReuseIdentifier: "ArticleCell") // Configure the TableView to use our class as the Data Source tableView.dataSource = self // Create a new instance of NewsFetcher to do our fetching let fetcher = NewsFetcher() // Ask fetcher to get latest articles // This is an asynchronous call // Code between { ... } will be executed when the data has been fetched // Note: Result is a Swift type that captures either success or failure in a single enum fetcher.getLatestArticles { [weak self] (result: Result<[NewsItem], NewsFetcherError>) in switch result { case .success(let newArticles): // If fetching was successful, set the articles variable from ViewController with new articles self?.articles = newArticles // The tell the tableView it should reload its data self?.tableView.reloadData() case .failure(let error): // If fetching failed, print the error print(error.localizedDescription) } } } } extension ViewController: UITableViewDataSource { func numberOfSections(in tableView: UITableView) -> Int { return 1 } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return articles.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { //// Complete me with cells that show the data from articles return UITableViewCell() } }
-
Run the app by hitting the play button. We will need to wait while data is fetched, then we should see a scrollable table of items. The table is beautiful....but the rows are empty.
-
We need to use the data from
articles
to populate each row. This is done by configuring ourUITableViewCells
in thecellForRow:
method:func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "ArticleCell", for: indexPath) cell.textLabel?.text = articles[indexPath.row].title return cell }
-
Now one more time, hit that play button and run the app. After the data is fetched, we should see a scrollable table of
NewsItems
. 🎉 -
The last step is to form a startup and become app billionaires!! 🤑 🤑 🤑