You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Jan 19, 2025. It is now read-only.
Copy file name to clipboardExpand all lines: _posts/2018-09-09-ios-notification-content-extensions.md
+17-33Lines changed: 17 additions & 33 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -16,32 +16,22 @@ authors: [fabrizio_duroni]
16
16
17
17
---
18
18
19
-
During a workshop I recently attended I had the opportunity to explore a new interesting app extension type available in
20
-
the iOS SDK: Notification Content App Extension. This extension has been added by Apple in iOS 10. By using this extension it is possible to customize the UI of your push and local notification. In this way you can show more engaging notification to your users :grin:.
19
+
During a workshop I recently attended I had the opportunity to explore a new interesting app extension type available in the iOS SDK: Notification Content App Extension. This extension has been added by Apple in iOS 10. By using this extension it is possible to customize the UI of your push and local notification. In this way you can show more engaging notification to your users :grin:.
21
20
Let's see an example where we create a notification with custom UI using this extension type. To do that I will use some assets taken from the [nasa photo journal](https://photojournal.jpl.nasa.gov/"nasa photo journal"). You can find the complete example [in this github repository](https://github.com/chicio/Notification-Content-Extension-Example"notification content extension example").
22
-
Let's start from the beginning: add a Notification Content Extension to your app. To do that just select the + button
23
-
in the target section that appears after selecting the xcodeproj file.
21
+
Let's start from the beginning: add a Notification Content Extension to your app. To do that just select the + button in the target section that appears after selecting the xcodeproj file.
24
22
25
-
{% include blog-lazy-image.html description="add target" width="1500" height="885" src="/assets/images/posts/notification-content-extension-add-target.jpg" %}
23
+
{% include blog-lazy-image.html description="Add a new Notification Content Extension target to the app" width="1500" height="885" src="/assets/images/posts/notification-content-extension-add-target.jpg" %}
26
24
27
-
The extension that is created contains a `NotificationViewController` that adheres to the `UNNotificationContentExtension`.
28
-
The documentation for this protocol says:
25
+
The extension that is created contains a `NotificationViewController` that adheres to the `UNNotificationContentExtension`. The documentation for this protocol says:
29
26
30
-
> An object that presents a custom interface for a delivered local or remote notification.
31
-
The UNNotificationContentExtension protocol provides the entry point for a notification content app extension,
32
-
which displays a custom interface for your app’s notifications. You adopt this protocol in the custom
33
-
UIViewController subclass that you use to present your interface. You create this type of extension to improve the
34
-
way your notifications are presented, possibly by adding custom colors and branding, or by incorporating media and
35
-
other dynamic content into your notification interface.
27
+
> An object that presents a custom interface for a delivered local or remote notification. The UNNotificationContentExtension protocol provides the entry point for a notification content app extension, which displays a custom interface for your app’s notifications. You adopt this protocol in the custom UIViewController subclass that you use to present your interface. You create this type of extension to improve the way your notifications are presented, possibly by adding custom colors and branding, or by incorporating media and other dynamic content into your notification interface.
36
28
37
29
So if a `UIViewController` inside a Notification Content Extension adhere to the `UNNotificationContentExtension` we are able to access to the notification content and we can customize its UI. In the extension there's also a `MainInterface.storyboard` that contains a single controller associated with the `NotificationViewController` previously mentioned. We can use this storyboard to customize the notification UI using interface builder.
38
30
So let's start by defining the interface in the storyboard. Below in the image there's the final result.
39
31
40
-
{% include blog-lazy-image.html description="notification storyboard" width="1500" height="885" src="/assets/images/posts/notification-content-extension-storyboard-notification.jpg" %}
32
+
{% include blog-lazy-image.html description="Customize the notification UI with the storyboard contained in the new created extension" width="1500" height="885" src="/assets/images/posts/notification-content-extension-storyboard-notification.jpg" %}
41
33
42
-
Then we can fill the UI with the notification content we receive in the `func didReceive(_ notification:
43
-
UNNotification)` of the `NotificationViewController` controller that implements the protocol shown above. Below you
44
-
can find its source code.
34
+
Then we can fill the UI with the notification content we receive in the `func didReceive(_ notification: UNNotification)` of the `NotificationViewController` controller that implements the protocol shown above. Below you can find its source code.
45
35
46
36
```swift
47
37
importUserNotifications
@@ -64,9 +54,7 @@ class NotificationViewController: UIViewController, UNNotificationContentExtensi
64
54
}
65
55
```
66
56
67
-
Now to test our controller and our new notification UI, we can create a local notification. We will use some data taken
68
-
from the nasa photo journal. We will create a `NasaLocalNotificationBuilder` that contains all the notification creation logic. This is
69
-
the final result.
57
+
Now to test our controller and our new notification UI, we can create a local notification. We will use some data taken from the nasa photo journal. We will create a `NasaLocalNotificationBuilder` that contains all the notification creation logic. This is the final result.
70
58
71
59
```swift
72
60
importUserNotifications
@@ -75,7 +63,7 @@ class NasaLocalNotificationBuilder {
notificationContent.body="Long press to see you daily nasa photo"
@@ -122,7 +110,7 @@ class NasaLocalNotificationBuilder {
122
110
]
123
111
returnself
124
112
}
125
-
113
+
126
114
funcbuild() {
127
115
let trigger =UNTimeIntervalNotificationTrigger(timeInterval: 5, repeats: false)
128
116
let request =UNNotificationRequest(identifier: "NasaDailyPhoto",
@@ -133,8 +121,7 @@ class NasaLocalNotificationBuilder {
133
121
}
134
122
```
135
123
136
-
Then we can call the notification builder in the main controller of the app `ViewController` to generate the
137
-
notification.
124
+
Then we can call the notification builder in the main controller of the app `ViewController` to generate the notification.
138
125
139
126
```swift
140
127
classViewController: UIViewController {
@@ -149,15 +136,12 @@ class ViewController: UIViewController {
149
136
}
150
137
```
151
138
152
-
Now we have to go back in our notification content extension and set some attribute in its `info.plist`. In
153
-
particular we have to set:
139
+
Now we have to go back in our notification content extension and set some attribute in its `info.plist`. In particular we have to set:
154
140
155
-
*`UNNotificationExtensionCategory` to the notification category that we want to customize. In our case we use
156
-
`NasaDailyPhoto`, the value we previously set in the builder
157
-
*`UNNotificationExtensionDefaultContentHidden` to hide the standard notification content when the user long press
158
-
the notification.
141
+
*`UNNotificationExtensionCategory` to the notification category that we want to customize. In our case we use `NasaDailyPhoto`, the value we previously set in the builder
142
+
*`UNNotificationExtensionDefaultContentHidden` to hide the standard notification content when the user long press the notification.
159
143
* if needed it is possible also to set the `UNNotificationExtensionInitialContentSizeRatio` to a value different than
160
-
1 to customize the aspect ration of our notification.
144
+
1 to customize the aspect ration of our notification.
161
145
162
146
We're ready to test our implementation. Below you can find a video with the final result of our implementation.
Copy file name to clipboardExpand all lines: _posts/2018-09-18-refactoring-if-chain-of-responsibility.md
+19-42Lines changed: 19 additions & 42 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -12,57 +12,35 @@ seo:
12
12
authors: [francesco_bonfadelli]
13
13
---
14
14
15
-
*In this post my colleague [Francesco Bonfadelli](https://www.linkedin.com/in/fbonfadelli/"Francesco Bonfadelli")
16
-
will show you how to transform a nested if structure into a chain of responsibility.*
15
+
*In this post my colleague [Francesco Bonfadelli](https://www.linkedin.com/in/fbonfadelli/"Francesco Bonfadelli") will show you how to transform a nested if structure into a chain of responsibility.*
17
16
18
17
---
19
18
20
-
In this post I am going to describe a step by step process used to transform a nested if structure into a chain of responsibility.
21
-
The purpose of this operation is to make the code easier to read, thus to change without introducing errors.
22
-
We will also get for free a structure that will be able to apply a more generic set of rules than the one defined at the beginning.
23
-
The code of this post is based on a piece of code used to satisfy a real business need,
24
-
we just removed the business related details.
19
+
In this post I am going to describe a step by step process used to transform a nested if structure into a chain of responsibility. The purpose of this operation is to make the code easier to read, thus to change without introducing errors. We will also get for free a structure that will be able to apply a more generic set of rules than the one defined at the beginning.
20
+
The code of this post is based on a piece of code used to satisfy a real business need, we just removed the business related details.
25
21
The language used is java.
26
22
27
-
#### The process in short
23
+
#### The process in short
24
+
28
25
* Flatten the if structure into a flat sequence of `if` clauses
29
26
* Extract each condition and the related action into a single class
30
27
* Create a common interface for all the extracted conditions
31
28
* Put all the conditions into a list
32
-
* Loop over the list and return the first action for which the condition is satisfied
29
+
* Loop over the list and return the first action for which the condition is satisfied
33
30
34
31
#### The need
35
-
It seemed a normal day of work when one of our managers called a meeting
36
-
to inform us of a very urgent feature that should be put in production
37
-
within 2 days.
38
-
So, as it usually happens in this case, between the deriving chaos and the tons of alignment
39
-
meetings that continuously interrupted us,
40
-
we produced a code that basically "worked", but it was a bit chaotic.
41
-
Luckily we were able at least to write the tests.
42
-
So, once we put in production the feature, we decided to immediately refactor the piece of code.
43
-
44
-
#### The process
45
-
We are going to see a step by step refactor of a specific class
46
-
that transforms the if-nested structure into a chain of responsibility.
47
-
48
-
We are not going to change the tests because they work as an acceptance test for our use case. In an ideal world,
49
-
with a lot of time available,
50
-
we would also write the tests of all the classes we are going to extract and simplify the current test.
51
-
But, you know, we are not in an ideal world 😅.
52
-
The idea behind this refactor is to proceed with small steps,
53
-
possibly using the IDE functionality (I used IDEA which is very good at it),
54
-
and run the tests after every operation.
55
-
Also, after each step there is a commit, not only to allow everyone to follow the evolution of the code through the commits,
56
-
but also to allow us to simply use ```git checkout .``` in case of errors, in order to come back to the previous working version.
57
-
All of this, allows us to keep the code strictly under control and avoid to introduce bugs during the refactoring.
58
-
I will use the diff syntax to show the differences between some pieces of code.
59
-
Please keep in mind that I will use it in order to highlight *only the main differences*
60
-
between one commit and the other and it won't be the exact diff you can get with git.
32
+
33
+
It seemed a normal day of work when one of our managers called a meeting to inform us of a very urgent feature that should be put in production within 2 days. So, as it usually happens in this case, between the deriving chaos and the tons of alignment meetings that continuously interrupted us, we produced a code that basically "worked", but it was a bit chaotic.
34
+
Luckily we were able at least to write the tests. So, once we put in production the feature, we decided to immediately refactor the piece of code.
35
+
36
+
#### The process
37
+
38
+
We are going to see a step by step refactor of a specific class that transforms the if-nested structure into a chain of responsibility. We are not going to change the tests because they work as an acceptance test for our use case. In an ideal world, with a lot of time available, we would also write the tests of all the classes we are going to extract and simplify the current test. But, you know, we are not in an ideal world 😅.
39
+
The idea behind this refactor is to proceed with small steps, possibly using the IDE functionality (I used IDEA which is very good at it), and run the tests after every operation. Also, after each step there is a commit, not only to allow everyone to follow the evolution of the code through the commits, but also to allow us to simply use ```git checkout .``` in case of errors, in order to come back to the previous working version. All of this, allows us to keep the code strictly under control and avoid to introduce bugs during the refactoring. I will use the diff syntax to show the differences between some pieces of code. Please keep in mind that I will use it in order to highlight *only the main differences* between one commit and the other and it won't be the exact diff you can get with git.
61
40
62
41
#### The initial code
63
-
Here you can find the code we were not very proud of.
64
-
In particular, I report the nested if structure, which is the part we are going to refactor.
Here you can find the code we were not very proud of. In particular, I report the nested if structure, which is the part we are going to refactor. ([Source code](https://github.com/bonfa/IfRemovingARealUseCase/blob/a6681dd088d06244878e0527e87b4c6b5bbfd50d/src/main/java/it/fbonfadelli/hand_baggage/HandBaggageInformationFactory.java))
66
44
67
45
```java
68
46
publicclassHandBaggageInformationFactory {
@@ -99,14 +77,13 @@ public class HandBaggageInformationFactory {
99
77
```
100
78
101
79
#### The execution
80
+
102
81
##### 1. Flatten the if structure
103
82
104
83
The idea here is to transform the nested if structure into a flat sequence of `if` clauses in order to isolate
105
84
and explicit each single condition.
106
-
To do so with very small steps, we are going to remove the `else` part of each `if` clause, by transforming
107
-
such part into an `if` clause whose condition is the negation of the original one.
108
-
In the following piece of code, you can notice how the outer if-else has become a couple of `if` clauses,
109
-
one for the original condition `flight.isOneWay()` and the other one with the opposite condition `!flight.isOneWay()`
85
+
To do so with very small steps, we are going to remove the `else` part of each `if` clause, by transforming such part into an `if` clause whose condition is the negation of the original one.
86
+
In the following piece of code, you can notice how the outer if-else has become a couple of `if` clauses, one for the original condition `flight.isOneWay()` and the other one with the opposite condition `!flight.isOneWay()`
0 commit comments