Memorize21 is a classical Memory Game and is my very first iOS Development project.
- Compatibility
- Screens
- Tech Stack
- Used Tools
- Architecture
- Code comments
- App Store
- Learning Journey
- Fastlane
- Contribution Guidelines
- Credits
- Release Notes
- As of version 3 of the App, only iOS/iPadOS 16.2+ are supported!
If you have the time to look at my code, you will notice an unusual amount of additional code comments which I have put along the lines. These comments are for my own learning and documentation purposes and probably would not appear in such a way in production code.
This App is available on the App Store, ready and free to be installed on your personal iPhone or iPad 😉
Past and upcoming beta versions of my App are available for Testing on TestFlight! DM me on Twitter if you want to test an upcoming release and I will send you an invite.
Feature Request and Bugs can be reported by opening a new issue. I might have a look at them 😁
I am reflecting my whole iOS Development learning journey in one giant XMind MindMap. Rather than day by day journal entries, you will find all the different topics I have faced on my way so far. You will find the MindMap in this repo 😉
- MVVM helps you to respect the separation of concerns design principle
- Is completely decoupled from the Model
- Is reactive and always reflects the current state of the model
- (The struct) Is created and thrown away all the time. Only the 'var body' sticks around for a very long time
- Don't need any state of their own
- Supposed to be "stateless" and drawing what the current state of the Model is
- Is a Self-referencing protocol and cannot be used as a normal type
- Use @State purposely and sparingly
- @State is a "source of truth" so it is better not something which belongs to the Model
- @State is only used to give temporary state to a var
- @State vars are marked private because no one else can access them anyway
- @State var will cause the View to rebuild its body anytime the data where the @State var is pointing to, changes. (This is like an @ObservedObject but on a random piece of data (instead of a ViewModel).) In the new version of the body, the @State var will continue to point the the data in the heap.
- @State makes a space for the var in the heap because the View struct is read-only
- Interoperates the Model for the View
- The model layer is the foundation of an app's architecture.
- Holds the permanent state of the app
- Swift Access Control
- Make things private by default and change them afterwards when you see that you need to access them from other place in your code
- internal (this is default): it can be accessed from anywhere in your code
- All shapes are also Views, they inherit from the View protocol
- SwiftUI Doc with examples
- Built-in shapes
- The func fill() is a generic function where the 'S' is a don't care (but since there's a 'where S: ShapeStyle', it becomes a "care a little bit").
- Only changes can be animated. This includes the following three things:
- ViewModifier arguments
- Shapes
- The comings and goings (existence or not) of Views in the UI
- Animation is showing the user changes that have already happened
- How to create simple animations
- Implicit Animations
- Less important kinds of animation
- Golden rule: only animates view modifiers for views which are already on screen
- View that are coming on screen or going of screen, can be animated with the .transition modifier
- All ViewModifier arguments that precede the animation modifier will always be animated.
- Eg. whenever scary and upsideDown changes, the opacity/rotationEffect will be animated:
- Without .animation(), the changes to opacity/rotation would appear instantly (not animated) on screen.
- Important: ViewModifiers after the animation modifier, will NOT be animated!
- .animation modifier does not work on containers
Text("Hello World")
.opacity(scary ? 1 : 0)
.rotationEffect(Angle.degrees(upsideDown ? 180 : 0))
.animation(Animation.easeInOut)
- Explicit Animations
- Is much more of a common way of doing animations
- Are independent of implicit animations when used in combination
- Only animates shapes and view modifiers
- Are used for user 'intent functions'
- We don't attach a modifier to a view, instead we ask SwiftUI to animate the precise change we want to make.
- Transitions
- A transition determines how a view appears/disappears on the screen.
- Transitions have their own animations: Transition.scale.animation()
- Are good for making the comings and goings of views looking smooth
- There are about 4 precanned transitions which are used the most
- AnyTransition is a typed erased transition
- Advanced Transitions
- References:
- The system default font of a Text is: San Francisco
- Have a look at Google Fonts for choosing your custom fonts
- For adding custom fonts in SwiftUI have a look at: How to add custom fonts in SwiftUI
- Sean Allen: How to upload and distribute an App
- Are you an App Store developer who is tired of clicking through the "compliance" question every time you submit a build?
- Complying with Encryption Export Regulations
- Automating the encryption compliance check
- A StoreKit configuration file lets us mock and create some fake products
- Testing: We can simulate a failed transaction by selecting the TipStoreKitConfiguration file, then via Editor -> Fail Transactions or Enable Interrupted Purchase
The fastest steps which I took to setup fastlane for this project were the following:
- Install fastlane:
brew install fastlane
- In the project directory: ``fastlane init``` and follow the instructions (Don't use 'fastlane init swift' yet, as it is still in beta and just creates a mess at the moment. See also https://docs.fastlane.tools/getting-started/ios/fastlane-swift/)
- Have a look at my Ruby file
- Create an App specific password in your Apple account: https://appleid.apple.com/account/manage -> Security
- Run lanes with e.g:
fastlane beta
- In case that you run out of 'Distribution' certificates, check the Certificates section in your Apple Developer account and delete unused certificates.
Follow the Arrange, Act and Assert Pattern for Unit Testing.
- Arrange inputs and targets:
- Does the test require any objects or special settings?
- Does it need to prep a database?
- Does it need to log into a web app?
- Act on target behavior:
- This step should call the function/method/API, or whatever needs to be tested.
- It should focus on the target behavior.
- Assert expected outcomes:
- This step should elicit some sort of response.
- Then the response should be judged for correctness.
Follow the Given-When-Then style to write the UI-Tests from a user perspective.
- Include "self documenting code."
- Additionally, include descriptive comments in order to improve readability. -Aim for comments that allow other programmers to understand your code without having to work through your entire classes/methods.
- Pull requests should be kept to a reasonable size.
- Pull requests should be descriptive, answer the following questions:
- What was the problem?
- What did you do to improve it?
- How do you know it is a working solution?/What tests did you do?
- Why do you believe this is the right solution?
- Why is this the best solution for the problem?
- Review/proofread your pull request before submission. Following this guide.
- CMD + B: build the project
- CMD + R: build and run the App in the simulator
- CMD + SHIFT + K: clean build folder
- CMD + SHIFT + O: open quick search
- CMD + SHIFT + J: highlight the selected open file in the navigator
- CMD + SHIFT + L: open up the library (Snippets, Media, Colors, SF Symbols)
- Tunde Adegoroye for the TipJar (with StoreKit2) part
Made with a 🙂 Simon Berner