Swift Programming Idea Part 4:map all the things!

Source: Internet
Author: User
Tags closure

Swift Programming Idea Part 4:map all the things!

2015-10-22 837

Article Directory
  1. 1. array vs. optional type
  2. 2. map () acting on an optional type
  3. 3. back to our example
  4. 4. Let's use map .
  5. 5. where is the problem?
  6. 6. FlatMap () to help.
  7. 7. use init as a closing packet
  8. 8. the ultimate Swift code
  9. 9. Take a look back at our OBJC code
  10. 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!

      1. Lines of Codes, refers to how many lines of code
      2. 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!

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.