Using this pattern can help achieve loose coupling and can keep domain objects persistence ignorant.
Finally, it is a way of centralising the handling of the domain objects.
If you just started learning how to build iOS apps, you might’ve felt overwhelmed by an endless list of things you should know. I’ve been there and I think I’m still there in a way.
Today, I’d like to share with you guys things I wish I had known before getting a foot into the door.
Because simply put, it’s next to impossible to understand all the moving parts in your code since they’re all tangled with one another, especially if you’re a newbie to Swift.
At the very beginning, it might be more helpful to just accept things as they are. Just follow the tutorial step to make the work done.
And then when you get more comfortable with how it works, you could get further into a low level of how this works.
People often first learn the tricks of a framework, and then move on to the language. That’s actually not the right way to go.
The simple reason here is that if you know about the underlying language, it helps you understand how the framework works. If you have no idea about the trades of a a language, there is no way you will understand why something is done a certain way in the framework.
Don’t just read, implement. I’ve often seen developers read through tutorials or sometimes even whole books without anything much to show for it. However, my biggest concern is how much would you retain if you just read ?
Start with an app that you feel most comfortable. And add some function to it day by day. Even a tiny app also has its problem to solve. You wont believe what you would get after time.
If you’ve read enough articles about the iOS development, I bet you’ve stumbled upon an article about which way is better to create a user interface. In my opinion, you need to learn both of them.
Every company and every developer has their own taste in this matter but I do think you should go with the storyboard if you just start learning it.
It’s more intuitive and easier to see the visual change whenever you do something. And you might not even know what you can do with each UI component yet. Familiarize yourself with all the common components and auto layout enough before moving into creating all in code.
If you get that far with programmatic UI, figure out when one thing is more beneficial and how it’s better than the other. The time will come when you have to create a custom UI in code as if you’re heavily using the storyboard.
By the time you’re familiar with Swift, it will dawn on you that just making it work is not enough. You need to think about the maintenance aspect of an app, is it relatively easy to add a feature to the code base? is it easy to fix a bug when it’s found? is it easy to unit test?
When you’re working on a big code base and it’s not well-structured, you will find it extremely difficult to make a change or add another feature on top of that. It will get to a point where you made a change but not sure if it had any side effect on somewhere else in the code that leads to another bug.
That’s when design patterns come in the play. It’s all about how we structure code.
Try to learn different design patterns and apply them to your code base for practice. It will give you an insight into what should be considered to make the code base better.
Mastering a technology on your own is great, but sometimes you learn a lot by just looking at the code of others. Be it your colleagues or random tutorials on the internet, try to find why someone approaches a problem in a certain way — and ask questions if necessary.
It’s also important for developers to realize that it’s impossible to know everything, but the knowledge is out there — you just need to Google it. As a beginner, if you’re stuck there is high probability that someone like you had the same problem in the past and the solution is somewhere out there in the internet (this often happens to the veterans too!)
Thank you for your time!


The Quality of Service (QoS) class classifies what you want dispatchQueue to do. Indicates the importance of your app by specifying the quality of the task. When scheduling tasks, the system prioritizes tasks with higher service classes. Higher priority tasks are faster than lower priority tasks and are performed using more resources, which typically requires more energy than lower priority tasks. You can ensure your app's responsiveness and energy efficiency by specifying exactly the right QoS class for what your app does.
userInteractive > userInitiated > default > utility > background
actions that interact with the user, such as working on the main thread, refreshing the user interface, or performing animations. focus on responsiveness and performance.
The task is almost instantaneous.
this class assigns it to tasks that provide immediate results for what the user is doing or prevent the user from using the app. for example, you can load the contents of the email that you want to display to the mercenary. you need immediate results, such as opening documents saved as user-initiated tasks,or performing tasks when a user clicks something in the user interface. work is required to continue user interaction. focus on responsiveness and performance.
Tasks like seconds or less are almost instantaneous.
The default quality of service class. Assign this class to a task or queue that your app starts or uses to perform active tasks on behalf of the user. This QoS is not used by developers to classify tasks. QoS is used as the default for unspecified operations and runs at the GCD global queue level.
a quality of service class for tasks that are not actively tracked by the user. tasks that take time to complete and do not require immediate results, such as downloading or importing data. utility operations typically have progress bars that are visible to the user. it focuses on providing a balance between responsiveness, performance and energy efficiency.
The operation takes a few seconds to a few minutes.
tasks that work in the background and are not visible to the user, such as indexing, synchronization, and backup. focus on energy efficiency.
Tasks that take a considerable amount of time and require minutes or hours
There are no quality of service classes. This indicates that there is no QoS information and signals that QoS should be inferred into the system. If a thread uses a legacy API, the thread can have unspecified QoS.
Reference:
When sending tasks to global concurrent queues, they do not specify a direct priority. Instead, specify a Quality of Service (QOS) class property: this indicates the importance of the task and helps the GCD determine the priorities to assign to the task.
// Serial Queue DispatchQueue.main.sync { } // CRASH! DispatchQueue.main.async { } DispatchQueue(label: "com.CustomSerialQueue").sync { } DispatchQueue(label: "com.CustomSerialQueue").async { } // Concurrent Queue DispatchQueue.global().sync { } DispatchQueue.global().async { } DispatchQueue(label: "com.CustomConcurrentQueue", attributes: .concurrent).sync { } DispatchQueue(label: "com.CustomConcurrentQueue", attributes: .concurrent).async { }
let serialQueue = DispatchQueue(label: "serialQueue")
serialQueue.sync {
for i in 0...3{
print("\(i) [serial_sync_1]")
}
print("--------------------------")
}
serialQueue.sync {
for i in 0...5{
print("\(i) [serial_sync_1]")
}
print("--------------------------")
}
for i in 0...5{
print(i)
}
======== Result ========
0 [serial_sync_1]
1 [serial_sync_1]
2 [serial_sync_1]
3 [serial_sync_1]
--------------------------
0 [serial_sync_2]
1 [serial_sync_2]
2 [serial_sync_2]
3 [serial_sync_2]
--------------------------
0
1
2
3
let serialQueue = DispatchQueue(label: "serialQueue")
serialQueue.async {
for i in 0...3{
print("\(i) [serial_async_1]")
}
print("--------------------------")
}
serialQueue.async {
for i in 0...3{
print("\(i) [serial_async_2]")
}
print("--------------------------")
}
for i in 0...5 {
print(i)
}
======== Result ========
0
0 [serial_async_1]
1
1 [serial_async_1]
2
2 [serial_async_1]
3
3 [serial_async_1]
4
--------------------------
0 [serial_async_2]
5
1 [serial_async_2]
2 [serial_async_2]
3 [serial_async_2]
--------------------------
DispatchQueue.global().sync {
for i in 0...3{
print("\(i) [global_sync_1]")
}
print("--------------------------")
}
DispatchQueue.global().sync {
for i in 0...3{
print("\(i) [global_sync_2]")
}
print("--------------------------")
}
for i in 0...3 {
print(i)
}
======== Result ========
0 [global_sync_1]
1 [global_sync_1]
2 [global_sync_1]
3 [global_sync_1]
--------------------------
0 [global_sync_2]
1 [global_sync_2]
2 [global_sync_2]
3 [global_sync_2]
--------------------------
0
1
2
3
DispatchQueue.global().async {
for i in 0...3{
print("\(i) [global_async_1]")
}
print("--------------------------")
}
DispatchQueue.global().async {
for i in 0...3 {
print("\(i) [global_async_2]")
}
print("--------------------------")
}
for i in 0...3 {
print(i)
}
======== Result ========
0
0 [global_async_2]
0 [global_async_1]
1
1 [global_async_2]
1 [global_async_1]
2
2 [global_async_1]
3
2 [global_async_2]
3 [global_async_1]
3 [global_async_2]
--------------------------
--------------------------