Unwrap - Learn Swift interactively on your iPhone.

Overview

Unwrap logo

Twitter: @twostraws

Unwrap is an app that helps you learn Swift faster and more effectively.

At its core lies almost 100 video lessons that teach all the fundamentals of the Swift programming language, with each lesson backed up by an interactive review.

Once you’ve made some progress learning, you can dive into a selection of practice activities that make you write code by tapping, dragging, or typing, find errors, predict program output, and more. There are also daily challenges that test your overall language knowledge once per day, helping your new skills really sink in.

Unwrap app is available to download for free on the App Store. I’ve made the code available so that anyone who wants to can see how I structure my code and perhaps learn from it. If you’d like to help you’re most welcome to and there are many opportunities, but make sure you read the contribution guidelines first.

Trying it yourself

Unwrap is written using Xcode 10.2 and Swift 5.0. All the CocoaPods are checked in to this repository, so you should be able to clone this and build it immediately by opening Unwrap.xcworkspace.

As far as I know the app is feature complete, but there are likely to be errors all over the place at least to begin with – if you hit problems, either building or running the app, please let me know.

Contribution guide

Any help you can offer with this project is most welcome, and trust me: there are opportunities big and small, so that someone with only a few weeks of Swift experience can help.

However, before you start please read the LICENSE.md and CONTRIBUTING.md files. Although all the source code of Unwrap is available under the MIT license, the assets are not redistributable – please see the license for more detail.

If you’d like to help, here are some suggestions ordered from most easy to most difficult. I’ve added documentation to most if not all of the code, but there’s also a separate document in this repository called CONTRIBUTING.md that documents how the code is structured and how it works.

Easy

  1. Just try running the app and let me know if you hit any problems.
  2. I’ve written a huge amount of all-new content for this app, so if (and when!) you see any typos please correct them and open a PR.
  3. If you spot any redundant code, or code that repeats itself that can sensible be refactored not to repeat, you’re welcome to clean it up. Any unused code should be deleted rather than just commented out.
  4. If you can write (sensible!) solutions for Free Coding problems that aren’t currently accepted, please add them.
  5. If you see any Sixty Seconds chapters that don’t have a postscript (alert message shown between the chapter text and review), and you think there’s something important to add there, add it.
  6. Write new tests. It doesn’t matter how small they might seem, tests are always appreciated and won’t require you to modify any of the core code.

Intermediate

  1. If you find any bugs and can fix them, by all means do.
  2. If you spot any performance hotspots that can be resolved smoothly, go for it.
  3. All the practice activities have their data stored as JSON. I’ve tried to create samples of each of them, but it would be awesome to add more.
  4. Right now the app is available only in English. We could look at localizing all the text, but I have concerns partly because Swift continues to change and partly because the videos will get in the way. If you have suggestions, let me know!
  5. Did I already mention adding tests?

Advanced

  1. Although I’m pretty happy with the app’s architecture, it could always be improved – if you have suggestions, let me know!
  2. I’ve added the basics of theme support, but it’s not implemented or tested yet. This could be expanded to work everywhere, and new themes could be added.
  3. The storyboard started off small and grew far too big for its boots. This is particularly annoying because many screens are similar. Some of the UI is now built in code already. To resolve this we could switch to building even more UI in code, starting with a direct copy of the storyboard, then try to refactor it so that similar view controllers are created using shared code.

Again, please make sure you read the LICENSE.md and CONTRIBUTING.md files before you start just to avoid problems.

Credits

Unwrap was designed and built by Paul Hudson. Hacking with Swift, Swift in Sixty Seconds, Unwrap, and the Unwrap logo are all copyright © Paul Hudson 2019.

Unwrap is built using some third-party frameworks and fonts: DZNEmptyDataSet, Font Awesome, MKRingProgressView, QuickLayout, SDWebImage, Sourceful, Zephyr, and SwiftEntryKit. Their licenses are stored inside their respective Pods directories, and are repeated inside the app’s credits screen.

Swift, the Swift logo, Xcode, Instruments, Cocoa Touch, Touch ID, AirDrop, iBeacon, iPhone, iPad, Safari, App Store, watchOS, tvOS, Mac and macOS are trademarks of Apple Inc., registered in the U.S. and other countries.

Unwrap includes an iMessage sticker pack that incorporates a variety of logos from around the Swift community – these are used with permission, and we're grateful to each person or project for granting that permission:

If you liked Unwrap and want more like it, I have a whole website full of free Swift tutorials.

Comments
  • Problem in a Daily Challenge question #50

    Problem in a Daily Challenge question #50

    Fixes that the constants created do not match the constants used when summing.

    Is there a way to test this? The son file is loaded than shuffled? What are the thoughts on having a debug mode that would load and show all the questions? Something as simple as having a long press on the "Predict the Output" button.

    opened by mike011 11
  • Added 2 new answers for a Free Coding Question.

    Added 2 new answers for a Free Coding Question.

    Added 2 new answers for a Free Coding Question, in which user has type code that doubles all the elements of an array.

    I'm working to add 4-5 more new answers to the same question.

    opened by heyrahulrs 10
  • Typo:

    Typo: "by", expected: "be"

    Addresses #213

    I have fixed SwiftLint warnings. I also resolved an issue with Extension tests:

    • cleanString6.toAnonymizedVariables() is compared to anonymizedString6
    • the expression returns "..." and is compared with " ... "
    • I have changed the anonymizedString6 value from " ... " to "..."

    Tested on:

    • iPhone 12 Simulator
    • iOS version 15.0
    opened by erikdrobne 9
  • Persist User state on NSUbiquitousKeyValueStore

    Persist User state on NSUbiquitousKeyValueStore

    Since the app is now universal,I wanted to be able to persist user progress between devices. I have tried to accomplish this with NSUbiquitousKeyValueStore, using the same logic @twostraws built into the app for saving to UserDefaults. Its 99% there.

    The last issue is, and I hope that you can help steer me into the correct direction to resolve this, that when the app is open on two devices at the same time, the trailing device is not updating its UI in response to NSUbiquitousKeyValueStore.didChangeExternallyNotification being observed. Ideally, because having two devices with the app open at the same time is a real probability, the not in use device should update and refresh its tableviews to correspond with the values saved in NSUKVS. Currently, the data is received but the UI does not reflect newest changes. However, if you exit and restart the app, the newest changes will be visible.

    How should I refresh the data to display on the inactive device without exiting the app? reloadData doesn't do anything and I have tried a couple different AppDelegate functions without success. I suspect it has to do with the coordinator pattern being used. I have a couple videos on that subject to watch tomorrow but in the meantime...

    opened by wayni208 9
  • Tour grammar fix

    Tour grammar fix

    Hopefully this works as intended, I am very much a newbie: am trying to submit a small grammar fix for the Tour JSON and not submit the project files changed to allow me to build locally. Please help me learn how to do this better :)

    opened by SuzGupta 6
  • NewsDataSource - Unexpected nil User

    NewsDataSource - Unexpected nil User

    First off, I want to say that the app looks awesome! 😃 I ran into a compilation issue on the way to work that I thought I would file here. I might just be missing something so I apologize in advance if that's the case.

    Hardware

    • Xcode 9.3
    • iPhone X Simulator (11.4)

    Error

    I see the following error:

    Fatal error: Unexpectedly found nil while unwrapping an Optional value
    

    for this line

    // NewsDataSource.swift
    var containsNewArticles: Bool {
        get {
            if let newestArticleID = articles.first?.id {
                // This line here
                if newestArticleID > User.current.latestNewsArticle {
                    return true
                }
            }
         set {
        ....
    }
    

    Possible Solution

    A quick fix I added to get the app to compile is to conditionally unwrap the User.current as so:

    if let user = User.current, newestArticleID > user.latestNewsArticle {
    

    However, I think it would help to understand why User.current was nil in the first place to see if this is the best fix. There are other places where User.current is being used so it could possibly affect other areas.

    opened by ajfigueroa 6
  • Dealing with the '…' ellipsis issue by homogenising to three periods

    Dealing with the '…' ellipsis issue by homogenising to three periods

    I hope I've done this right. I've largely followed the pattern of other similar homogenising blocks so hopefully it is ok. If not, would be interesting to see where I've made mistakes.

    opened by robinlmp 4
  • Remove level-up chime to prevent background audio interruption

    Remove level-up chime to prevent background audio interruption

    Currently, the level up chime completely stops any music/podcast I have playing in the background.

    This pull request resumes the background audio after the chime has finished playing.

    p.s: I considered using the .mixWithOthers category option to have both the chime and background audio play simultaneously, but this is not optimal for the videos

    opened by almaleh 4
  • Localization

    Localization

    I saw some user-facing strings that are not wrapped in an NSLocalizedString and I was wondering about the plans of localizing the app?

    It might be a good idea to prepare for that, and it could be a nice task to get an overview of the code base. :)

    (I might want to pick this one up myself 😄)

    opened by BasThomas 4
  • Show unread badge on reused cells in the NewsViewController

    Show unread badge on reused cells in the NewsViewController

    This PR fixes an issue with the blue badges added in #103 whereby reused cells would sometimes show the incorrect badge state because the badge state was not reset on reused cells.

    opened by julianschiavo 4
  • Make it a universal app

    Make it a universal app

    It feels so much better when you can use an iPhone app on an iPad as well. If there are no bigger concerns why this app shouldn't allow universal builds then I like the user to decide which device fits best to use the app.

    #29

    opened by lunij 4
  • Infinite score in challenges.

    Infinite score in challenges.

    Somehow I got into a state on my iPad where I could keep clicking "Continue" and it would add the challenge score to my total.

    So after tapping "continue" the screen doesn't change. So I hit the Continue button again and saw that it was increasing my total progress. Then I just hit the "Continue button as fast as I could and boom I got over a million points.

    Steps to reproduce

    I have no idea how I got here. I just did the challenge. I was working on it in bed and fell asleep then woke up and kept going. Now I can get infinite points.

    Expected behavior

    When I hit continue it would score and then at least deactivate the "Continue" button. Or it would take me to another screen saying I needed to wait a day for the next challenge.

    I'm not sure how this is supposed to work so I was just playing around with the app. There are a few different UX paths this could take.

    Actual behavior

    Here is a video of the behavior.

    Environment

    • iOS Version:
      • 15.2
    • Unwrap App Version:
      • 1.5
    • Device:
      • iPad 9th gen
    opened by td-gonzales 0
  • WebViewController: Actually display back/forward/share buttons

    WebViewController: Actually display back/forward/share buttons

    Upon fixing #232, I discovered it actually was all already in there, so all I did was display the buttons. If there was a reason for not displaying them, please tell me, so I can try to do it right.

    Works fine for me in simulator, and no new failing tests or linting errors due to my commit.

    opened by d12bb 1
  • Add share menu and open in Safari to articles in news section

    Add share menu and open in Safari to articles in news section

    The news section in this app is quite limiting as one has to read an article in the app. It would be great if one could open them in the browser, or it had a share menu to send it to other apps for reading later or sharing on social media

    Steps to reproduce

    1. Go to News section
    2. Tap on article
    3. See there's no button other than reload

    Expected behavior

    1. Have two buttons for opening in Safari and sharing
    opened by d12bb 0
  • Local Notification support for Daily Challenges?

    Local Notification support for Daily Challenges?

    I've been trying to get a streak going but every so often I forget to open the app so daily reminders could be of use — is this a worthy improvement I could work on that others would like?

    I'm thinking something really simple like choosing what time you want the notifications to trigger and then that's it 😊 perhaps a "Configure Notifications" cell in the Challenges table or something, that presents/pushes a new view controller

    opened by SunburstEnzo 0
  • Opening app on M1 Mac resets progress

    Opening app on M1 Mac resets progress

    The problem

    It seems that if the app is opened on an M1 Mac, that the users progress is reset. I haven’t tried it myself, mainly because I don’t use an M1 (yet).

    Reported on the slack channel here: https://hackingwithswift.slack.com/archives/CJBQQ7J4C/p1634786078000800

    Expected behaviour

    I suppose either the app should be set to not target macOS, or it should not wipe progress when it is installed.

    Unsure which versions were being used. Have asked and will update when I get a reply.

    opened by robinlmp 0
  • Accessibility: Add better label to section video play buttons

    Accessibility: Add better label to section video play buttons

    From a user: "There is a “link” that plays the video for the section, but from an accessibility point of view all that is spoken is “link”. Could you consider adding a label like “Play Video” so that the Voiceover speaks “Play Video link”. "

    good first issue 
    opened by twostraws 0
Owner
Paul Hudson
Creator of Hacking with Swift, author of books about iOS, macOS, watchOS, and tvOS, public speaker, Rubik's cube enthusiast, and herder of my kids.
Paul Hudson
Charter - A Swift mailing list client for iPhone and iPad

Due to costs and lack of interest, I’ve had to take down the Charter service. If you’re interested in running your own copy, get in touch and I can se

Matthew Palmer 526 Dec 24, 2022
IOS - Unofficial app for Swift Evolution

EVOlution - iOS The goal of this project is for the version 1.0 was: bring to iOS the experience provided by Swift Evolution website. Now we are shift

EVOlution App 235 Dec 19, 2022
Unwrap value from Dictionary in Swift

JHUnwrap Unwrap value from Dictionary in Swift Example let dict: Dictionary<String, Any> = [ "name": "Lilei", "age": 20, "

HaoCold 2 Dec 22, 2021
A library that adds a throwing unwrap operator in Swift.

ThrowingUnwrap A simple package to add a throwing unwrap operator (~!) to Optionals in Swift. Import Add this to the package-wide dependencies in Pack

Allotrope 3 Aug 27, 2022
🎁 Unwrap an optional or throw an error if nil (or crash the program).

Unwrap Or Throw (or Die!) ?? Unwrap an optional or throw an error if nil (or crash the program). Not invented here. The idea for unwrap or die and unw

Alejandro Martínez 7 Nov 30, 2022
iPhone and iPod Touch version of Skeleton Key: is an addictive and unique puzzle game in which you shift keys around the board unlocking treasure chests. Made with cocos2d-iphone.

Skeleton Key (iOS) Skeleton Key is an addictive and unique puzzle game in which you shift keys around the board unlocking treasure chests. It's availa

null 117 Jun 6, 2022
Learn how to structure your iOS App with declarative state changes using Point-Free's The Composable Architecture (TCA) library.

Learn how to structure your iOS App with declarative state changes using Point-Free's The Composable Architecture (TCA) library.

Tiago Henriques 0 Oct 2, 2022
Joseph Miller 0 Jan 7, 2022
A self-taught project to learn Swift.

30 Days of Swift Hi Community I am Allen Wang, a product designer and currently learning Swift. This project was totally inspired by Sam Lu's 100 Days

Allen Wang 11.4k Dec 31, 2022
This project server as a demo for anyone who wishes to learn Core Data in Swift.

CoreDataDemo This project server as a demo for anyone who wishes to learn Core Data in Swift. The purpose of this project is to help someone new to Co

null 1 May 3, 2022
A repository for showcasing my knowledge of the Swift programming language, and continuing to learn the language.

Learning Swift (programming language) I know very little about programming in the Swift programming language. This document will go over all my knowle

Sean P. Myrick V19.1.7.2 2 Nov 8, 2022
IOS-Bootcamp-Examples - Learn to Swift while building apps - With IOS Development Bootcamp

IOS-Bootcamp-Examples Learn to Swift while building apps - With IOS Development

Bilge Çakar 9 Dec 21, 2022
CleanArchitecture - Helping project to learn Clean Architecture using iOS (Swift)

Clean Architecture Helping project to learn Clean Architecture using iOS (Swift)

Alliston 2 Dec 5, 2022
Learn about how SoulverCore can give Swift "better than regex" data parsing features (for many common tasks)

String Parsing with Soulver Core A declarative & type-safe approach to parsing data from strings SoulverCore gives you human-friendly, type-safe & per

Soulver 140 Nov 23, 2022
You will learn how to scan QR code with iOS framework.

QR Code Scanner You will learn how to scan QR code with in iOS without using any library. It is as simple to scan QR code in iOS. In this example, We

Nitin Aggarwal 11 Dec 8, 2022
Learn to Code While Building Apps - The Complete iOS Development Bootcamp

Xylophone Our Goal The goal of this tutorial is to dive into a simple iOS recipe - how to play sound and use an Apple library called AVFoundation. The

The App Brewery 83 Jan 6, 2023
A simple self-development challenge application that aimed to learn

Movie List Challenge A simple self-development challenge application that aimed to learn "The Composable Architecture" basics and build a reactive str

Nicat Muzaffarli 1 Oct 30, 2021
Learn to Code While Building Apps - The Complete iOS Development Bootcamp

BMI Calculator Our Goal The goal of this tutorial is to learn more about Optionals, solidify your understanding of the MVC design pattern and to intro

The App Brewery 52 Oct 6, 2022
FlightLayout is a light weight, and easy to learn layout framework as an extension of the UIView.

FlightLayout Introduction FlightLayout is a light weight, and easy to learn layout framework as an extension of the UIView. Functionally, it lives som

Anton 23 Apr 21, 2022