Swift Programming Idea Part 4:map all the things!
2015-10-22 837
Article Directory
- 1. array vs. optional type
- 2. map () acting on an optional type
- 3. back to our example
- 4. Let's use map .
- 5. where is the problem?
- 6. FlatMap () to help.
- 7. use init as a closing packet
- 8. the ultimate Swift code
- 9. Take a look back at our OBJC code
- Conclusion
Olivier Halligon, original link, original date: 2015-10-11
Translator: ray16897188; proofreading: Prayer; Final: numbbbbb
Address of article series:
- Swift programming ideas, Part one: saving ponies
- Swift programming ideas, Part II: MAP Methods for arrays
- Swift Programming Ideas Part III: Structures and Classes
In the previous articles in this series we learned how to use map
and flatMap
manipulate arrays (arrays). Today we continue to explore how to use and for alternative types (optionals) as well as many other types map
flatMap
.
Array vs. optional types
Looking back, after learning the previous article, we already know that Array<T>
the corresponding map()
and flatMap()
function signatures are:
1 2 3
|
The method of acting on the array<t> T- array<u> array<array<u>
|
It means that you can convert an array of elements of an element type to an array with a given type of transform: T->U
T
element U
. The Array<T>
call map( transform: T->U )
method returns one Array<U>
, just as simple.
Well, not surprisingly, Optional<T>
map()
flatMap()
The function signature is very similar to the following:
1 2 3
|
The method of acting on the optional<t> T- optional<u> optional<optional<u>
|
Does it look like it?
Map () that acts on an optional type
So map
what exactly does the method do to the Optional<T>
type (also called T?
)?
In fact, it is very simple: and the role Array<T>
of the same, the map
method will be Optional<T>
taken out of the content, using the specified transform: T->U
method to make the conversion, and then wrap the results into a new Optional<U>
.
If you think about it, it Array<T>.map
's very similar to what you're doing: This method Array<T>
Optional<T>
uses a function transformation for each element (corresponding to it) transform
and encapsulates the converted value in a new one Array<U>
(corresponding to that Optional<U>
), which is returned as a result.
Back to our example
So how does this help with the sample code we've been working on?
In our most new version of the code, there is a String?
type itemDesc["icon"]
, we wanted to convert it to one, UIImage
but UIImage(named:)
asked to pass in a String
type of parameter, not String?
type, so we need to have a value in the selection (non nil
) The internal String
value is passed in.
One solution is to use an optional binding (Optional binding):
1 2 3 4 5 6
|
UIImage? Let Iconname = itemdesc[String { UIImage (Named:iconname) else { Nil }
|
But the amount of code is too large for such a simple operation.
In a previous example we used a different (very elegant) way to use the nil
-union operator ??
.
1 2
|
Let Iconname = itemdesc[String "")
|
This is possible, but it succeeds because when iconName
it is nil
, we are actually using UIImage(named: "")
the initialization method, which is returned when an empty string is passed in nil
. However, this workaround is not very good because we are relying on the attributes of the initialization method (which is returned when an empty string is passed in nil
).
Let's use map.
So why not map
? Essentially, we want to Optional<String>
nil
unpack it when it's not, convert it to an UIImage
object and UIImage
return it, isn't that a great use case?
Try:
1 2
|
Let Iconname = itemdesc[String Item.icon = Iconname. UIImage (Named:imagename)}
|
Wait a minute.... compilation does not pass. Can you guess why?
Where's the problem?
The problem in the above code is UIImage(named: …)
also to return an optional type: if there is no corresponding picture for a given, you name
cannot create one UIImage
, so in this case the initialization method is failed (failable), and returns nil
, is perfectly reasonable.
So the problem is that we give map
this one as a String
parameter and return ... A UIImage?
type--because the initialization method of a picture can fail , it is returned nil
. Take a look at map
the signature of the method, what it wants is a T->U
type of closure, and the closure returns a U?
type. In our example, the U
UIImage?
whole map
expression will return a U?
type, that is ... A UIImage??
type ... Yes, a double optional type, scared to the baby!
FlatMap () to help.
flatMap()
As with map
similar, but doing is a T->U?
conversion (not T->U
), it turns the result "flattened" (as the name implies) into an optional type of single weight. This is exactly what we need!
1 2
|
Let Iconname = itemdesc[String UIImage (Named:imagename)}
|
In practice, flatMap
the following work has been done:
- If
iconName
nil
So, it returns directly nil
(but the return type or UIImage?
)
- If
iconName
not nil
, it puts the transform
iconName
actual value on the action, attempts to String
create one with this UIImage
and returns the result--the result itself is already a UIImage?
type, so if UIImage
the initialization method fails, The return result is nil
.
In short, item.icon
itemDesc["icon"] as? String
a non-null value is only available if the non-null, and UIImage(named: imageName)
the initialization method succeeds.
This is ??
better and more authentic than using the spoofing initialization method.
Use init as a closing packet.
Further, since Xcode 7 can now .init
expose this type of constructor (constructors) through the type's properties, the code above can be more compact.
This means that it UIImage.init
is essentially a method of receiving String
and returning UIImage?
, so we can call it directly as a parameter flatMap
, instead of wrapping it in a closed bag!
1 2
|
Let Iconname = itemdesc[String Item.icon = Iconname.flatmap (UIImage. Init
|
Oh, whoa! It's magical!
Well, some people say it's hard to read, and in order to make the code clearer, it's more like using an explicit closure. But it's just a matter of personal preference, and it's good to know that it works.
The ultimate Swift code
Here's how you'll apply this lesson to the previous code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21st
|
structListItem { var icon:UIImage? var title:String var URL:Nsurl StaticFuncListitemsfromjsondata(Jsondata:nsdata?) -I [ListItem] { GuardLet Jsondata = Jsondata, Let JSON =Try?Nsjsonserialization.Jsonobjectwithdata (Jsondata, Options: []), Let Jsonitems = JSONAs?array<Nsdictionary>else {return []} Return Jsonitems.flatmap {(Itemdesc:Nsdictionary)ListItem?Inch GuardLet title = itemdesc["title"]As?String, let urlstring = Itemdesc[ "url"] as? string, let url = nsurl (String: urlstring) else {return Nil} let iconname = Itemdesc[ "icon"] as? string let icon = iconname.flatmap { uiimage (named: $0)} return Span class= "type" >listitem (Icon:icon, Title:title, Url:url) } } Span class= "line" > |
Take a look back at our OBJC code
Take a moment to compare our final Swift code with the initial OBJC code. We've changed a lot of things.
If you take a closer look at the OBJC and Swift code, you will find that Swift's code is not so small (OBJC is 5+15 LoC1, compared to Swift's LoC), but it is much more secure .
In particular we use guard
, try?
and as?
will force us to check whether all types are as in the period, OBJC code will not care about these and therefore may crash????。 So although the code is quite equal, the OBJC code is more dangerous.
Conclusion
Through this series of articles, I want you to realize: don't try to translate your OBJC code into Swift. Instead, you need to rethink your code and re-imagine your code. Starting with a blank state, it's always better to rewrite your code in the mind with Swift's ideas than you would translate the OBJC code.
I didn't say it was an easy thing to do. When you're used to writing code with OBJC, familiar with its patterns and the way you write code, it can take some time to make a change of mind. But that's definitely more of a benefit.
This is the final part of the Swift Programming Ideas Series 2. Now you're going to go crazy about the new Swift project and put the swift programming ideas into your head.
I wish to use Swift programming happy, and ...
MAP everything, FLATMAP everything!
- Lines of Codes, refers to how many lines of code
- I'm going to post a closing article, leave a word about monads and really end the series. Don't worry, there are many more Swift articles coming soon.
Swift Programming Idea Part 4:map all the things!