{"id":10548,"date":"2019-12-26T00:00:00","date_gmt":"2019-12-26T00:00:00","guid":{"rendered":"https:\/\/dev95.site\/building-better-views-part-i\/"},"modified":"2019-12-26T00:00:00","modified_gmt":"2019-12-26T00:00:00","slug":"building-better-views-part-i","status":"publish","type":"post","link":"https:\/\/dev95.site\/ar\/building-better-views-part-i\/","title":{"rendered":"Building Better Views (Part I)"},"content":{"rendered":"<div id=\"dev95-1059477546\" class=\"dev95-- dev95-entity-placement\" role=\"region\" aria-label=\"\u0627\u0644\u0625\u0639\u0644\u0627\u0646\u0627\u062a\"><script async=\"async\" data-cfasync=\"false\" src=\"https:\/\/pl27862732.profitableratecpmnetwork.com\/2ad7a50e0bbc23ac6801d7b77c501463\/invoke.js\"><\/script>\r\n<div id=\"container-2ad7a50e0bbc23ac6801d7b77c501463\"><\/div><\/div><div id=\"dev95-2441592295\" class=\"dev95-before-content dev95-entity-placement\" role=\"region\" aria-label=\"\u0627\u0644\u0625\u0639\u0644\u0627\u0646\u0627\u062a\"><p style=\"text-align: center;\"><strong>Stop wasting time on dead links! \ud83d\uded1 This smart platform automatically detects your device and country to give you the exact best offer instantly. Check it out now 100% free! \ud83d\udc47<\/strong><br data-sfc-root=\"ep\" data-sfc-pl=\"|||[]\" data-complete=\"true\" data-copy-service-computed-style=\"font-family: Arial, sans-serif, &quot;Noto Color Emoji&quot;; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(10, 10, 10);\" \/><a href=\"https:\/\/www.profitableratecpmnetwork.com\/pvhx5mbcc?key=ff7d362db3c20bc86fad685cc94f1fc4\">\ud83d\udd17 <strong class=\"rQesXe MPyX\" data-sfc-cp=\"\" data-sfc-root=\"ep\" data-complete=\"true\" aria-owns=\"action-menu-parent-container\" data-copy-service-computed-style=\"font-family: Arial, sans-serif, &quot;Noto Color Emoji&quot;; font-size: 16px; font-weight: 700; margin: 0px; text-decoration: none; border-bottom: 0px rgb(10, 10, 10);\">[Click here]<\/strong><\/a><\/p>\n<\/div><div>\n<p>As iOS developers, a lot of our work involves taking models from a server, and transforming them to be displayed on an iPhone or iPad. This sounds like a job for some declarative architecture. \ud83e\udd14<\/p><div id=\"dev95-1059156900\" class=\"dev95- dev95-entity-placement\" role=\"region\" aria-label=\"\u0627\u0644\u0625\u0639\u0644\u0627\u0646\u0627\u062a\"><center>\r\n<script>\r\n  atOptions = {\r\n    'key' : '4ba6b6513c00e0ba76511f798ae56401',\r\n    'format' : 'iframe',\r\n    'height' : 50,\r\n    'width' : 320,\r\n    'params' : {}\r\n  };\r\n<\/script>\r\n<script src=\"https:\/\/www.highrevenueformat.com\/4ba6b6513c00e0ba76511f798ae56401\/invoke.js\"><\/script>\r\n\t<\/center><\/div>\n<p><!--preview-snippet--><\/p>\n<blockquote class=\"twitter-tweet\" data-theme=\"light\">\n<p lang=\"en\" dir=\"ltr\">If you ask 3 programmers how to define MVVM, expect to get 7 different responses.<\/p>\n<p>\u2014 \u2728 Joe Fabisevich\u2122 \u2728 (@mergesort) <a href=\"https:\/\/twitter.com\/mergesort\/status\/720706593982062592?ref_src=twsrc%5Etfw\">April 14, 2016<\/a><\/p><\/blockquote>\n<p> <script async src=\"https:\/\/platform.twitter.com\/widgets.js\" charset=\"utf-8\"><\/script><\/p>\n<p>Confession: I\u2019ve never fully bought into MVVM. I don\u2019t think it\u2019s worse than MVC. I use View Models as a place to store state and actions for View Controllers, and preferably stateless functions for manipulating data. In my experience, things become harder to maintain when they start becoming a crutch, as a place to put your code if it doesn\u2019t neatly fall into the Model, View, or Controller label.<\/p>\n<p>With this in mind, I realized we need an answer for configuring our views in a way that\u2019s maintainable, and ultimately transforms one or multiple models into a view. This led me to the idea of <code class=\"language-text\">ViewData<\/code>. I started working on this with <a href=\"https:\/\/twitter.com\/shengjundong\">@shengjundong<\/a> at <a href=\"https:\/\/www.timehop.com\/\">Timehop<\/a>, and have been using it successfully across apps of varying sizes since.<\/p>\n<p>There are three parts to this approach:<\/p>\n<ol>\n<li>\n<p>A <code class=\"language-text\">UIView<\/code> instance. This is your standard view that you\u2019ll be displaying in an app. It can be a regular class, or a custom subclass as you need.<\/p>\n<\/li>\n<li>\n<p>A <code class=\"language-text\">ViewData<\/code> protocol. This is what\u2019s going to keep track of the data that needs to be displayed in your view. Most commonly this will be a slice of a model, used specifically for rendering the view.<\/p>\n<\/li>\n<li>\n<p>A <code class=\"language-text\">configure(viewData: ViewData)<\/code> function. This is what\u2019s going to map your View to your ViewData.<\/p>\n<\/li>\n<\/ol>\n<p><span class=\"gatsby-resp-image-wrapper\" style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 970px; \"><br \/>\n      <span class=\"gatsby-resp-image-background-image\" style=\"padding-bottom: 100%; position: relative; bottom: 0; left: 0; background-image: url('data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFUklEQVQ4y21UC0yTZxS9LQtumiybS5Ytm8mWbEtm4haibmjmYyqiDOaDMhCGDwQRgT5oS1tooQ8BASnCFFFkiETnEsQJKqLRqagR1KHimDIEfACCD+RZ2r\/\/PUtxblmyk5x8N9\/97jm5ufkujU73ox4iSiYiIWKT110icvqHkSskhlyyaBqdLyMCCKV26ZxloLBYprCNoAUyEABaGQVp4Z4X8YwlTNRPk6mdiFBULnUFr6cmIi+Hb8BXzoDwqDH\/sNUDPoE+44I5BeS7wP2BXygvWRyGgJlL+BOAyX8VSGOBl0eQCES3PUflMQlrLOSYtyLIHaW6xao0sNYKUWsDFDq0rrDV6iM6flZZ4TRtYZiyGVorhFgtTs0Owsz1SUzZ2yEdFxUUJqkrRk2ji0Nj3fJUcEoW2JAhsj7LDYNZbFfuQ73BjZvaXpSkdMCYD9GSy6IlT4Qlj6E2M\/uvQtAaOShOBy8a9FlIg9PmT4fcCKTlAoZMAYYsht7KA+p8rorr5P2xV911SQ+Ea4oOzrI85TQ72PqCrowCQJXGgx\/PwoefzgERDtcRVssrOuK06IrXuboT9OhJTGXojdykOMNl0ddREFLJ20JruDllCJXaNlZnjbBcd4fVpi4YNg84zVuBtQrelrMDRBeIJmKT\/s+maDmOyVaL1bJIbo6WM5LNqE94iEup4Hrbcz5n7ecmE\/jXxG4YskYgN7RyVPwF1qQ\/ctvygcRUbiLCKzT6ke9kd6z2GYzZGG\/VkOkhehOy+HReNd+tKUHfiTx+fNLObUeKUWc\/xGZbP9vsgC0fbMmDaM1jKEx4+O5neJ36iCa5N2jueoYh6mwitJk8ajLizmU1d5zO5KeVCbhdGsv39icCdUm4WWflDa1NbMp\/BnM2OC1XFK12QG7kFiK8Sqg+ScL38QdYnwHoM1xOjQWdVxIZMOHBxV3oO2jg89ui0FAcBxzR8dELVYhBP5S3Gzg9ewzpW+Eyb2XEqLnicC2IHL4BNDrdb5YoTwE0OXi0N0kUYQLG0vm3y2ncXGbja0Xr0L5fjt4f1axoOs1yDLAC96A+\/IeYsQXQbhYxdzlmL5R5ppySJUWimVyBESphUyruNSjRfl8pnjmxFu1tcm6\/WQTHcTujSsc7b9QhpKWeZbU\/IXbwFqs7W6A3O\/HdRujNW0DZ21lKj4ioEackbcUq6glZGtlwMNTRcjYG\/NzEECwsdhtwtVLP2aeqOUoYhQojHNV1hwOPH0VYXa0rWNMRt6uxloB4CXmDaGDCFCrY8Y7E8w1BoJKnaxtPdylxqSXOfe7WRq7pjOe9jkRsc5hh69zFurYqNtw\/5s7o3ofMPnmTp4bqiRZW6CXv+4Bo1GcRvQ2iSyOlXtU4RVuxrmo3klEMjVCCZOyBjvfBwAeg4YNI4v1QohwJQgUU+AGR1UA5nR8+L40C0dzlngVBRItcE8k2ttzL4ggk45Bf8B5WokzQCoazYWy8GI70K5Fsa17HpsbVyO+J53IYXLtFFVKHl4ZZHcto89hKr0iXN\/2DkCdvUezA1PGd5mGOM7yqDFrsfK5w7ehPFAp6N7kLH8e78x5sFIqeK1x7kYxcZ0TNy\/dxA9Mo4tl7\/wr69xFtGJhK8sEZksDeCTSlg17LcYYfKoUK5dChAoa\/qYfnLtcZ\/svnD2lS8JM3SDn0pcQj6N9L\/0Xy8DxKHp5LqiFfybLHE8edU4cXy+yuNYcKhejrhUL0DbtzTZVxxD\/Uk5M9fZOShmdLdSPzycP\/RZojYDypHPpC4imyOIKoFfVEzeRNv5N3B66Q1fHtuJnHWD\/yNaU7vhnv8CX+AtC3t8Gk0oitAAAAAElFTkSuQmCC'); background-size: cover; display: block;\"><\/span>\n  <picture><source srcset=\"\/static\/0f600b07895848c61817aa8345f754af\/fc615\/view_data_diagram.avif 243w, \n\/static\/0f600b07895848c61817aa8345f754af\/b3175\/view_data_diagram.avif 485w,\n\/static\/0f600b07895848c61817aa8345f754af\/006d3\/view_data_diagram.avif 970w,\n\/static\/0f600b07895848c61817aa8345f754af\/b52ec\/view_data_diagram.avif 1455w,\n\/static\/0f600b07895848c61817aa8345f754af\/dbea6\/view_data_diagram.avif 1798w\" sizes=\"(max-width: 970px) 100vw, 970px\" type=\"image\/avif\"><source srcset=\"\/static\/0f600b07895848c61817aa8345f754af\/0e3e2\/view_data_diagram.webp 243w, \n\/static\/0f600b07895848c61817aa8345f754af\/749af\/view_data_diagram.webp 485w,\n\/static\/0f600b07895848c61817aa8345f754af\/dbca2\/view_data_diagram.webp 970w,\n\/static\/0f600b07895848c61817aa8345f754af\/bda17\/view_data_diagram.webp 1455w,\n\/static\/0f600b07895848c61817aa8345f754af\/f98ee\/view_data_diagram.webp 1798w\" sizes=\"(max-width: 970px) 100vw, 970px\" type=\"image\/webp\"><source srcset=\"\/static\/0f600b07895848c61817aa8345f754af\/8aea6\/view_data_diagram.png 243w, \n\/static\/0f600b07895848c61817aa8345f754af\/44c61\/view_data_diagram.png 485w,\n\/static\/0f600b07895848c61817aa8345f754af\/587b0\/view_data_diagram.png 970w,\n\/static\/0f600b07895848c61817aa8345f754af\/5b795\/view_data_diagram.png 1455w,\n\/static\/0f600b07895848c61817aa8345f754af\/8454b\/view_data_diagram.png 1798w\" sizes=\"(max-width: 970px) 100vw, 970px\" type=\"image\/png\"><br \/>\n          <img data-recalc-dims=\"1\" class=\"gatsby-resp-image-image\" src=\"https:\/\/i0.wp.com\/fabisevi.ch\/static\/0f600b07895848c61817aa8345f754af\/587b0\/view_data_diagram.png?w=1280&#038;ssl=1\" alt=\"A diagram explaining the interaction flow of ViewData\" title=\"A diagram explaining the interaction flow of ViewData\" loading=\"lazy\" decoding=\"async\" style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\">\n        <\/picture>\n    <\/span><\/p>\n<h5>An Example<\/h5>\n<p>Let\u2019s start with an example, where we\u2019re building a view to display a comment. It will have a few properties you\u2019d expect from a comment view. A commenter, their avatar, some text, and a timestamp. To make it easier to visualize, let\u2019s imagine it looks like this:<\/p>\n<p><span class=\"gatsby-resp-image-wrapper\" style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 710px; \"><br \/>\n      <span class=\"gatsby-resp-image-background-image\" style=\"padding-bottom: 61.31687242798354%; position: relative; bottom: 0; left: 0; background-image: url('data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAIAAADtbgqsAAAACXBIWXMAABYlAAAWJQFJUiTwAAABtElEQVQoz22Sy66qMBSGeWEfx7kTn8KBiSNCRAzl2tJSoOUWgygGVIR1sm3O3vuc+A2aTr7+61Jtt9stFgvTNCmljuP4vo8QKoqi67rrL7pfXC6X5\/O53++11Wqladp6vc6yTMmO47RtCwDzPMMnpmkCAM\/zNCGE7\/tt23LOq6oqy1JKWZZlGIZCiDzPhRBN0yhnmqZ5nsdxBADXdbW6rgFgGIbD4RCGISHEcZwoimzbZoxRShFCnPPPyVVVAUDf9wghjDEhxHXdOI6TJInjGP9FvFHVCSEAwPf9n2TlEEKCIMiyjDFGCGGMqbuUsq7roiiapsnz\/B\/5fr8jhBhjnPMwDNM0pZQGQaDC0zRVff5ftpL7vrcsy\/d9jDFCiFLqvTkej7Zte543DEP\/Zpom9dCP\/Hg8oigSQqRpyhgrioJSmmUZ51xKmaYpxlhKmSTJ6\/VSK\/ySy7JU8vV67fu+6zoVMo7j\/EZtCAA45xjjJEksy6qq6qvn0+kEALfbTSUHQSCldF33fD5\/\/xN1IoS22y3GeLlcIoTiONYMw1CDpZRGb8gnoigyTVPXdcMwdF1HCG02mz\/QKINyf3HcqgAAAABJRU5ErkJggg=='); background-size: cover; display: block;\"><\/span>\n  <picture><source srcset=\"\/static\/bb599d186a5165d938803a6110500edb\/fc615\/comment_example.avif 243w, \n\/static\/bb599d186a5165d938803a6110500edb\/b3175\/comment_example.avif 485w,\n\/static\/bb599d186a5165d938803a6110500edb\/6bc71\/comment_example.avif 710w\" sizes=\"(max-width: 710px) 100vw, 710px\" type=\"image\/avif\"><source srcset=\"\/static\/bb599d186a5165d938803a6110500edb\/0e3e2\/comment_example.webp 243w, \n\/static\/bb599d186a5165d938803a6110500edb\/749af\/comment_example.webp 485w,\n\/static\/bb599d186a5165d938803a6110500edb\/457aa\/comment_example.webp 710w\" sizes=\"(max-width: 710px) 100vw, 710px\" type=\"image\/webp\"><source srcset=\"\/static\/bb599d186a5165d938803a6110500edb\/8aea6\/comment_example.png 243w, \n\/static\/bb599d186a5165d938803a6110500edb\/44c61\/comment_example.png 485w,\n\/static\/bb599d186a5165d938803a6110500edb\/7131f\/comment_example.png 710w\" sizes=\"(max-width: 710px) 100vw, 710px\" type=\"image\/png\"><br \/>\n          <img data-recalc-dims=\"1\" class=\"gatsby-resp-image-image\" src=\"https:\/\/i0.wp.com\/fabisevi.ch\/static\/bb599d186a5165d938803a6110500edb\/7131f\/comment_example.png?w=1280&#038;ssl=1\" alt=\"A visual example of a commment box we're going to build in code\" title=\"A visual example of a commment box we're going to build in code\" loading=\"lazy\" decoding=\"async\" style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\">\n        <\/picture>\n    <\/span><\/p>\n<p>We start with a simple model. This is what we\u2019ll be later manipulating for display purposes.<\/p>\n<div class=\"gatsby-highlight\" data-language=\"swift\">\n<pre class=\"language-swift\"><code class=\"language-swift\"><span class=\"token keyword\">public<\/span> <span class=\"token keyword\">struct<\/span> <span class=\"token class-name\">Comment<\/span> <span class=\"token punctuation\">{<\/span>\n    <span class=\"token keyword\">let<\/span> text<span class=\"token punctuation\">:<\/span> <span class=\"token class-name\">String<\/span>\n    <span class=\"token keyword\">let<\/span> commenter<span class=\"token punctuation\">:<\/span> <span class=\"token class-name\">String<\/span>\n    <span class=\"token keyword\">let<\/span> createdAt<span class=\"token punctuation\">:<\/span> <span class=\"token class-name\">Date<\/span>\n    <span class=\"token keyword\">let<\/span> avatarURL<span class=\"token punctuation\">:<\/span> <span class=\"token constant\">URL<\/span><span class=\"token operator\">?<\/span>\n<span class=\"token punctuation\">}<\/span><\/code><\/pre>\n<\/div>\n<p>A simple <code class=\"language-text\">UIView<\/code> subclass to display the comment.<\/p>\n<div class=\"gatsby-highlight\" data-language=\"swift\">\n<pre class=\"language-swift\"><code class=\"language-swift\"><span class=\"token keyword\">public<\/span> <span class=\"token keyword\">final<\/span> <span class=\"token keyword\">class<\/span> <span class=\"token class-name\">CommentView<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token class-name\">UIView<\/span> <span class=\"token punctuation\">{<\/span>\n    <span class=\"token keyword\">let<\/span> titleLabel <span class=\"token operator\">=<\/span> <span class=\"token class-name\">UILabel<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span>\n    <span class=\"token keyword\">let<\/span> subtitleLabel <span class=\"token operator\">=<\/span> <span class=\"token class-name\">UILabel<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span>\n    <span class=\"token keyword\">let<\/span> statusLabel <span class=\"token operator\">=<\/span> <span class=\"token class-name\">UILabel<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span>\n    <span class=\"token keyword\">let<\/span> replyButton <span class=\"token operator\">=<\/span> <span class=\"token class-name\">UIButton<\/span><span class=\"token punctuation\">(<\/span>type<span class=\"token punctuation\">:<\/span> <span class=\"token punctuation\">.<\/span>custom<span class=\"token punctuation\">)<\/span>\n    <span class=\"token keyword\">let<\/span> avatarImageView <span class=\"token operator\">=<\/span> <span class=\"token class-name\">UIImageView<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span>\n<span class=\"token punctuation\">}<\/span> <\/code><\/pre>\n<\/div>\n<p>Now we get a little to the fun stuff.<\/p>\n<p>We\u2019ll make our first  <code class=\"language-text\">ViewData<\/code> protocol. This represents how we will render the data we\u2019re trying to populate the <code class=\"language-text\">UIView<\/code> with.<\/p>\n<div class=\"gatsby-highlight\" data-language=\"swift\">\n<pre class=\"language-swift\"><code class=\"language-swift\"><span class=\"token keyword\">protocol<\/span> <span class=\"token class-name\">CommentViewData<\/span> <span class=\"token punctuation\">{<\/span>\n    <span class=\"token keyword\">var<\/span> title<span class=\"token punctuation\">:<\/span> <span class=\"token class-name\">String<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token keyword\">get<\/span> <span class=\"token punctuation\">}<\/span>\n    <span class=\"token keyword\">var<\/span> subtitle<span class=\"token punctuation\">:<\/span> <span class=\"token class-name\">String<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token keyword\">get<\/span> <span class=\"token punctuation\">}<\/span>\n    <span class=\"token keyword\">var<\/span> timestamp<span class=\"token punctuation\">:<\/span> <span class=\"token class-name\">String<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token keyword\">get<\/span> <span class=\"token punctuation\">}<\/span>\n    <span class=\"token keyword\">var<\/span> replyText<span class=\"token punctuation\">:<\/span> <span class=\"token class-name\">String<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token keyword\">get<\/span> <span class=\"token punctuation\">}<\/span>\n    <span class=\"token keyword\">var<\/span> avatarURL<span class=\"token punctuation\">:<\/span> <span class=\"token constant\">URL<\/span><span class=\"token operator\">?<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token keyword\">get<\/span> <span class=\"token punctuation\">}<\/span>\n<span class=\"token punctuation\">}<\/span><\/code><\/pre>\n<\/div>\n<p>Let\u2019s conform our model to our <code class=\"language-text\">CommentViewData<\/code> protocol. This will be how we tell our <code class=\"language-text\">CommentView<\/code> how it should display our model whenever it comes across an instance of it.<\/p>\n<div class=\"gatsby-highlight\" data-language=\"swift\">\n<pre class=\"language-swift\"><code class=\"language-swift\"><span class=\"token comment\">\/\/ The original data source is made to conform to the protocol which we are using for display, CommentViewData<\/span>\n\n<span class=\"token keyword\">extension<\/span> <span class=\"token class-name\">Comment<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token class-name\">CommentViewData<\/span> <span class=\"token punctuation\">{<\/span>\n    \n    <span class=\"token keyword\">var<\/span> title<span class=\"token punctuation\">:<\/span> <span class=\"token class-name\">String<\/span> <span class=\"token punctuation\">{<\/span>\n        <span class=\"token keyword\">return<\/span> <span class=\"token keyword\">self<\/span><span class=\"token punctuation\">.<\/span>commenter\n    <span class=\"token punctuation\">}<\/span>\n    \n    <span class=\"token keyword\">var<\/span> subtitle<span class=\"token punctuation\">:<\/span> <span class=\"token class-name\">String<\/span> <span class=\"token punctuation\">{<\/span>\n        <span class=\"token keyword\">return<\/span> <span class=\"token keyword\">self<\/span><span class=\"token punctuation\">.<\/span>text\n    <span class=\"token punctuation\">}<\/span>\n    \n    <span class=\"token keyword\">var<\/span> replyText<span class=\"token punctuation\">:<\/span> <span class=\"token class-name\">String<\/span> <span class=\"token punctuation\">{<\/span>\n        <span class=\"token keyword\">return<\/span> <span class=\"token class-name\">NSLocalizedString<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string-literal\"><span class=\"token string\">\"Reply\"<\/span><\/span><span class=\"token punctuation\">,<\/span> comment<span class=\"token punctuation\">:<\/span> <span class=\"token string-literal\"><span class=\"token string\">\"Text for replying to a comment\"<\/span><\/span><span class=\"token punctuation\">)<\/span>\n    <span class=\"token punctuation\">}<\/span>\n    \n    <span class=\"token keyword\">var<\/span> replyImage<span class=\"token punctuation\">:<\/span> <span class=\"token class-name\">UIImage<\/span><span class=\"token operator\">?<\/span> <span class=\"token punctuation\">{<\/span>\n        <span class=\"token keyword\">return<\/span> <span class=\"token class-name\">UIImage<\/span><span class=\"token punctuation\">(<\/span>named<span class=\"token punctuation\">:<\/span> <span class=\"token string-literal\"><span class=\"token string\">\"reply\"<\/span><\/span><span class=\"token punctuation\">)<\/span>\n    <span class=\"token punctuation\">}<\/span>\n    \n    <span class=\"token keyword\">var<\/span> timestamp<span class=\"token punctuation\">:<\/span> <span class=\"token class-name\">String<\/span> <span class=\"token punctuation\">{<\/span>\n        <span class=\"token keyword\">return<\/span> <span class=\"token keyword\">self<\/span><span class=\"token punctuation\">.<\/span>createdAt<span class=\"token punctuation\">.<\/span>timeAgoSinceNow\n    <span class=\"token punctuation\">}<\/span>\n\n<span class=\"token punctuation\">}<\/span><\/code><\/pre>\n<\/div>\n<p>One thing to note is that the <code class=\"language-text\">avatarURL<\/code> property automatically conforms to the <code class=\"language-text\">CommentViewData<\/code>! As long as we plan to use it directly, we don\u2019t have to add it to our extension.<\/p>\n<p>Last but not least, we need to configure the <code class=\"language-text\">CommentView<\/code> with a <code class=\"language-text\">CommentViewData<\/code>.<\/p>\n<div class=\"gatsby-highlight\" data-language=\"swift\">\n<pre class=\"language-swift\"><code class=\"language-swift\"><span class=\"token keyword\">extension<\/span> <span class=\"token class-name\">CommentView<\/span> <span class=\"token punctuation\">{<\/span>\n\n    <span class=\"token keyword\">func<\/span> <span class=\"token function-definition function\">configure<\/span><span class=\"token punctuation\">(<\/span>viewData<span class=\"token punctuation\">:<\/span> <span class=\"token class-name\">CommentViewData<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token punctuation\">{<\/span>\n        <span class=\"token keyword\">self<\/span><span class=\"token punctuation\">.<\/span>titleLabel<span class=\"token punctuation\">.<\/span>text <span class=\"token operator\">=<\/span> viewData<span class=\"token punctuation\">.<\/span>title\n        <span class=\"token keyword\">self<\/span><span class=\"token punctuation\">.<\/span>subtitleLabel<span class=\"token punctuation\">.<\/span>text <span class=\"token operator\">=<\/span> viewData<span class=\"token punctuation\">.<\/span>subtitle\n        <span class=\"token keyword\">self<\/span><span class=\"token punctuation\">.<\/span>statusLabel<span class=\"token punctuation\">.<\/span>text <span class=\"token operator\">=<\/span> viewData<span class=\"token punctuation\">.<\/span>timestamp\n        <span class=\"token keyword\">self<\/span><span class=\"token punctuation\">.<\/span>replyButton<span class=\"token punctuation\">.<\/span><span class=\"token function\">setTitle<\/span><span class=\"token punctuation\">(<\/span>viewData<span class=\"token punctuation\">.<\/span>replyText<span class=\"token punctuation\">,<\/span> <span class=\"token keyword\">for<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token punctuation\">.<\/span>normal<span class=\"token punctuation\">)<\/span>\n        <span class=\"token keyword\">self<\/span><span class=\"token punctuation\">.<\/span>replyButton<span class=\"token punctuation\">.<\/span><span class=\"token function\">setImage<\/span><span class=\"token punctuation\">(<\/span>viewData<span class=\"token punctuation\">.<\/span>replyImage<span class=\"token punctuation\">,<\/span> <span class=\"token keyword\">for<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token punctuation\">.<\/span>normal<span class=\"token punctuation\">)<\/span>\n        <span class=\"token keyword\">self<\/span><span class=\"token punctuation\">.<\/span>avatarImageView<span class=\"token punctuation\">.<\/span><span class=\"token function\">setImage<\/span><span class=\"token punctuation\">(<\/span>from<span class=\"token punctuation\">:<\/span> viewData<span class=\"token punctuation\">.<\/span>avatarURL<span class=\"token punctuation\">)<\/span>\n    <span class=\"token punctuation\">}<\/span>\n\n<span class=\"token punctuation\">}<\/span><\/code><\/pre>\n<\/div>\n<p>We\u2019ve got everything configured in a nice declarative fashion, but how do we actually use this? This is in my opinion the best part. Let\u2019s look at the call-site.<\/p>\n<div class=\"gatsby-highlight\" data-language=\"swift\">\n<pre class=\"language-swift\"><code class=\"language-swift\">    <span class=\"token keyword\">func<\/span> <span class=\"token function-definition function\">tableView<\/span><span class=\"token punctuation\">(<\/span><span class=\"token omit keyword\">_<\/span> tableView<span class=\"token punctuation\">:<\/span> <span class=\"token class-name\">UITableView<\/span><span class=\"token punctuation\">,<\/span> cellForRowAt indexPath<span class=\"token punctuation\">:<\/span> <span class=\"token class-name\">IndexPath<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">-&gt;<\/span> <span class=\"token class-name\">UITableViewCell<\/span> <span class=\"token punctuation\">{<\/span>\n      <span class=\"token comment\">\/\/ My own homegrown solution, you're under no obligation to use it of course \ud83d\ude07<\/span>\n      <span class=\"token keyword\">let<\/span> cell <span class=\"token operator\">=<\/span> tableView<span class=\"token punctuation\">.<\/span><span class=\"token function\">dequeueReusableCell<\/span><span class=\"token punctuation\">(<\/span>forIndexPath<span class=\"token punctuation\">:<\/span> indexPath<span class=\"token punctuation\">)<\/span> <span class=\"token keyword\">as<\/span> <span class=\"token class-name\">GenericTableCell<\/span><span class=\"token operator\">&lt;<\/span><span class=\"token class-name\">CommentView<\/span><span class=\"token operator\">&gt;<\/span>\n        \n      <span class=\"token comment\">\/\/ This is of type `Comment`<\/span>\n      <span class=\"token keyword\">let<\/span> currentComment <span class=\"token operator\">=<\/span> <span class=\"token keyword\">self<\/span><span class=\"token punctuation\">.<\/span>comments<span class=\"token punctuation\">[<\/span>indexPath<span class=\"token punctuation\">.<\/span>row<span class=\"token punctuation\">]<\/span>\n    \n      <span class=\"token comment\">\/\/ Comment conforms to `CommentViewData`, so we can use it directly!<\/span>\n      cell<span class=\"token punctuation\">.<\/span>customView<span class=\"token punctuation\">.<\/span><span class=\"token function\">configure<\/span><span class=\"token punctuation\">(<\/span>viewData<span class=\"token punctuation\">:<\/span> currentComment<span class=\"token punctuation\">)<\/span>\n    \n      <span class=\"token keyword\">return<\/span> cell\n    <span class=\"token punctuation\">}<\/span><\/code><\/pre>\n<\/div>\n<p>And that\u2019s it! All you need to do is pass the original model object to the view, and as long as it conforms to the right protocol, you\u2019ve got it working without any intermediate objects.<\/p>\n<hr>\n<p>This may seem like a lot of boilerplate, and to be honest, it&#8217;s more than I would like. There are other languages with features such as <a href=\"https:\/\/github.com\/purescript\/documentation\/blob\/a15f4e6b40e0a8dc874285526afe13f3074b6d26\/language\/Types.md#row-polymorphism\">row polymorphism<\/a> or <a href=\"https:\/\/medium.com\/@ckoster22\/advanced-types-in-elm-extensible-records-67e9d804030d\">extensible records<\/a> which would make this easier. Until Swift supports these language features, or macros, or more powerful tooling that can fill the gaps, this is the best solution I\u2019ve found to enforcing good practices and leveraging compile-time safety for view configuration.<\/p>\n<hr>\n<p>Now you may also be thinking \u201csometimes my models don\u2019t map to how they\u2019re displayed one to one, how can I make that work?\u201d Follow along with <a href=\"https:\/\/fabisevi.ch\/2019\/12\/26\/building-better-views-part-ii\">part 2<\/a>, where we&#8217;ll cover that, and a few other questions you may have.<\/p>\n<p>As always, I&#8217;m excited to hear your thoughts, and am receptive to <a href=\"https:\/\/twitter.com\/mergesort\">feedback<\/a>!<\/p>\n<\/div>\n<div class=\"pvc_clear\"><\/div>\n<p id=\"pvc_stats_10548\" class=\"pvc_stats total_only  \" data-element-id=\"10548\" style=\"\"><i class=\"pvc-stats-icon large\" aria-hidden=\"true\"><svg aria-hidden=\"true\" focusable=\"false\" data-prefix=\"far\" data-icon=\"chart-bar\" role=\"img\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" viewBox=\"0 0 512 512\" class=\"svg-inline--fa fa-chart-bar fa-w-16 fa-2x\"><path fill=\"currentColor\" d=\"M396.8 352h22.4c6.4 0 12.8-6.4 12.8-12.8V108.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v230.4c0 6.4 6.4 12.8 12.8 12.8zm-192 0h22.4c6.4 0 12.8-6.4 12.8-12.8V140.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v198.4c0 6.4 6.4 12.8 12.8 12.8zm96 0h22.4c6.4 0 12.8-6.4 12.8-12.8V204.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v134.4c0 6.4 6.4 12.8 12.8 12.8zM496 400H48V80c0-8.84-7.16-16-16-16H16C7.16 64 0 71.16 0 80v336c0 17.67 14.33 32 32 32h464c8.84 0 16-7.16 16-16v-16c0-8.84-7.16-16-16-16zm-387.2-48h22.4c6.4 0 12.8-6.4 12.8-12.8v-70.4c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v70.4c0 6.4 6.4 12.8 12.8 12.8z\" class=\"\"><\/path><\/svg><\/i> <img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"16\" height=\"16\" alt=\"Loading\" src=\"https:\/\/i0.wp.com\/dev95.site\/wp-content\/plugins\/page-views-count\/ajax-loader-2x.gif?resize=16%2C16&#038;ssl=1\" border=0 \/><\/p>\n<div class=\"pvc_clear\"><\/div>\n<div id=\"dev95-3506789329\" class=\"dev95-after-content dev95-entity-placement\" role=\"region\" aria-label=\"\u0627\u0644\u0625\u0639\u0644\u0627\u0646\u0627\u062a\"><p style=\"text-align: center;\"><strong>Finally, a link that actually works for your region and device! \ud83c\udf0d Get instant access to the top exclusive offers tailored just for you right now. Don&#8217;t miss out, click here! \ud83d\udc47<\/strong><br data-sfc-root=\"ep\" data-sfc-pl=\"|||[]\" data-complete=\"true\" data-copy-service-computed-style=\"font-family: Arial, sans-serif, &quot;Noto Color Emoji&quot;; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(10, 10, 10);\" \/><a href=\"https:\/\/www.profitableratecpmnetwork.com\/uzeja8ahze?key=bc876be53d6ad0ff6370ab8ea030e479\"><strong>\ud83d\udd17 [Click here]<\/strong><\/a><\/p>\n<\/div>","protected":false},"excerpt":{"rendered":"<p>As iOS developers, a lot of our work involves taking models from a server, and transforming them to be displayed on an iPhone or iPad. This sounds like a job for some declarative architecture. \ud83e\udd14 If you ask 3 programmers<\/p>\n<div class=\"hosteria-entry-more\"><a href=\"https:\/\/dev95.site\/ar\/building-better-views-part-i\/\" class=\"no-underline font-light  group-hover:text-primary-800 dark:group-hover:text-primary-300 py-1\">Read more &gt;&gt;&gt;<\/a><\/div>\n<div class=\"pvc_clear\"><\/div>\n<p id=\"pvc_stats_10548\" class=\"pvc_stats total_only\" data-element-id=\"10548\" style=\"\"><i class=\"pvc-stats-icon large\" aria-hidden=\"true\"><svg aria-hidden=\"true\" focusable=\"false\" data-prefix=\"far\" data-icon=\"chart-bar\" role=\"img\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" viewbox=\"0 0 512 512\" class=\"svg-inline--fa fa-chart-bar fa-w-16 fa-2x\"><path fill=\"currentColor\" d=\"M396.8 352h22.4c6.4 0 12.8-6.4 12.8-12.8V108.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v230.4c0 6.4 6.4 12.8 12.8 12.8zm-192 0h22.4c6.4 0 12.8-6.4 12.8-12.8V140.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v198.4c0 6.4 6.4 12.8 12.8 12.8zm96 0h22.4c6.4 0 12.8-6.4 12.8-12.8V204.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v134.4c0 6.4 6.4 12.8 12.8 12.8zM496 400H48V80c0-8.84-7.16-16-16-16H16C7.16 64 0 71.16 0 80v336c0 17.67 14.33 32 32 32h464c8.84 0 16-7.16 16-16v-16c0-8.84-7.16-16-16-16zm-387.2-48h22.4c6.4 0 12.8-6.4 12.8-12.8v-70.4c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v70.4c0 6.4 6.4 12.8 12.8 12.8z\" class=\"\"><\/path><\/svg><\/i> <img loading=\"lazy\" decoding=\"async\" width=\"16\" height=\"16\" alt=\"Loading\" src=\"https:\/\/dev95.site\/wp-content\/plugins\/page-views-count\/ajax-loader-2x.gif\" border=\"0\" \/><\/p>\n<div class=\"pvc_clear\"><\/div>","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"fp_fajr_begins":"","fp_fajr_iqamah":"","fp_dhuhr_begins":"","fp_dhuhr_iqamah":"","fp_asr_begins":"","fp_asr_iqamah":"","fp_maghrib_begins":"","fp_maghrib_iqamah":"","fp_isha_begins":"","fp_isha_iqamah":"","fp_midnight":"","fp_midnight_name":"","fp_sunrise":"","fp_single_prayer_begins_title":"","fp_single_prayer_iqamah_title":"","fp_prayer_times_for_today":"","fp_hijra_date":"","fp_fajr_name":"","fp_dhuhr_name":"","fp_asr_name":"","fp_maghrib_name":"","fp_isha_name":"","fp_sunrise_name":"","fp_currentDate":"","fp_current_time":"","fp_current_title":"","fp_current_location":"","fp_masjid_name":"","fp_prayer_title":"","fp_next_prayer_iqamah_time":"","fp_next_prayer_iqamah_title":"","fp_next_prayer_begins_time":"","fp_next_prayer_begins_title":"","fp_next_prayer_title":"","_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_post_was_ever_published":false},"categories":[37],"tags":[],"class_list":["post-10548","post","type-post","status-publish","format-standard","hentry","category-posts"],"a3_pvc":{"activated":true,"total_views":4,"today_views":0},"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.7 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Building Better Views (Part I) - Dev95<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/dev95.site\/ar\/building-better-views-part-i\/\" \/>\n<meta property=\"og:locale\" content=\"ar_AR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Building Better Views (Part I) - Dev95\" \/>\n<meta property=\"og:description\" content=\"As iOS developers, a lot of our work involves taking models from a server, and transforming them to be displayed on an iPhone or iPad. This sounds like a job for some declarative architecture. \ud83e\udd14 If you ask 3 programmersRead more &gt;&gt;&gt;\" \/>\n<meta property=\"og:url\" content=\"https:\/\/dev95.site\/ar\/building-better-views-part-i\/\" \/>\n<meta property=\"og:site_name\" content=\"Dev95\" \/>\n<meta property=\"article:published_time\" content=\"2019-12-26T00:00:00+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/fabisevi.ch\/static\/0f600b07895848c61817aa8345f754af\/587b0\/view_data_diagram.png\" \/>\n<meta name=\"author\" content=\"dev95\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"\u0643\u064f\u062a\u0628 \u0628\u0648\u0627\u0633\u0637\u0629\" \/>\n\t<meta name=\"twitter:data1\" content=\"dev95\" \/>\n\t<meta name=\"twitter:label2\" content=\"\u0648\u0642\u062a \u0627\u0644\u0642\u0631\u0627\u0621\u0629 \u0627\u0644\u0645\u064f\u0642\u062f\u0651\u0631\" \/>\n\t<meta name=\"twitter:data2\" content=\"4 \u062f\u0642\u0627\u0626\u0642\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/dev95.site\\\/building-better-views-part-i\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/dev95.site\\\/building-better-views-part-i\\\/\"},\"author\":{\"name\":\"dev95\",\"@id\":\"https:\\\/\\\/dev95.site\\\/#\\\/schema\\\/person\\\/b807805ffe2916206b04d0938bce0298\"},\"headline\":\"Building Better Views (Part I)\",\"datePublished\":\"2019-12-26T00:00:00+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/dev95.site\\\/building-better-views-part-i\\\/\"},\"wordCount\":649,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/dev95.site\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/dev95.site\\\/building-better-views-part-i\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/fabisevi.ch\\\/static\\\/0f600b07895848c61817aa8345f754af\\\/587b0\\\/view_data_diagram.png\",\"articleSection\":[\"Posts\"],\"inLanguage\":\"ar\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/dev95.site\\\/building-better-views-part-i\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/dev95.site\\\/building-better-views-part-i\\\/\",\"url\":\"https:\\\/\\\/dev95.site\\\/building-better-views-part-i\\\/\",\"name\":\"Building Better Views (Part I) - Dev95\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/dev95.site\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/dev95.site\\\/building-better-views-part-i\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/dev95.site\\\/building-better-views-part-i\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/fabisevi.ch\\\/static\\\/0f600b07895848c61817aa8345f754af\\\/587b0\\\/view_data_diagram.png\",\"datePublished\":\"2019-12-26T00:00:00+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/dev95.site\\\/building-better-views-part-i\\\/#breadcrumb\"},\"inLanguage\":\"ar\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/dev95.site\\\/building-better-views-part-i\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"ar\",\"@id\":\"https:\\\/\\\/dev95.site\\\/building-better-views-part-i\\\/#primaryimage\",\"url\":\"https:\\\/\\\/fabisevi.ch\\\/static\\\/0f600b07895848c61817aa8345f754af\\\/587b0\\\/view_data_diagram.png\",\"contentUrl\":\"https:\\\/\\\/fabisevi.ch\\\/static\\\/0f600b07895848c61817aa8345f754af\\\/587b0\\\/view_data_diagram.png\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/dev95.site\\\/building-better-views-part-i\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/dev95.site\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Building Better Views (Part I)\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/dev95.site\\\/#website\",\"url\":\"https:\\\/\\\/dev95.site\\\/\",\"name\":\"Dev95\",\"description\":\"Your comprehensive digital platform for knowledge, services, tools, and entertainment.\",\"publisher\":{\"@id\":\"https:\\\/\\\/dev95.site\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/dev95.site\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"ar\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/dev95.site\\\/#organization\",\"name\":\"Dev95\",\"url\":\"https:\\\/\\\/dev95.site\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"ar\",\"@id\":\"https:\\\/\\\/dev95.site\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/i0.wp.com\\\/dev95.site\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/rbrrbr-6.png?fit=512%2C512&ssl=1\",\"contentUrl\":\"https:\\\/\\\/i0.wp.com\\\/dev95.site\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/rbrrbr-6.png?fit=512%2C512&ssl=1\",\"width\":512,\"height\":512,\"caption\":\"Dev95\"},\"image\":{\"@id\":\"https:\\\/\\\/dev95.site\\\/#\\\/schema\\\/logo\\\/image\\\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/dev95.site\\\/#\\\/schema\\\/person\\\/b807805ffe2916206b04d0938bce0298\",\"name\":\"dev95\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"ar\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/a70a73d950838b20cd80d7ebdc955737e802e8cd896044c5473b32b946c0662a?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/a70a73d950838b20cd80d7ebdc955737e802e8cd896044c5473b32b946c0662a?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/a70a73d950838b20cd80d7ebdc955737e802e8cd896044c5473b32b946c0662a?s=96&d=mm&r=g\",\"caption\":\"dev95\"},\"url\":\"https:\\\/\\\/dev95.site\\\/ar\\\/author\\\/mohammad\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Building Better Views (Part I) - Dev95","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/dev95.site\/ar\/building-better-views-part-i\/","og_locale":"ar_AR","og_type":"article","og_title":"Building Better Views (Part I) - Dev95","og_description":"As iOS developers, a lot of our work involves taking models from a server, and transforming them to be displayed on an iPhone or iPad. This sounds like a job for some declarative architecture. \ud83e\udd14 If you ask 3 programmersRead more &gt;&gt;&gt;","og_url":"https:\/\/dev95.site\/ar\/building-better-views-part-i\/","og_site_name":"Dev95","article_published_time":"2019-12-26T00:00:00+00:00","og_image":[{"url":"https:\/\/fabisevi.ch\/static\/0f600b07895848c61817aa8345f754af\/587b0\/view_data_diagram.png","type":"","width":"","height":""}],"author":"dev95","twitter_card":"summary_large_image","twitter_misc":{"\u0643\u064f\u062a\u0628 \u0628\u0648\u0627\u0633\u0637\u0629":"dev95","\u0648\u0642\u062a \u0627\u0644\u0642\u0631\u0627\u0621\u0629 \u0627\u0644\u0645\u064f\u0642\u062f\u0651\u0631":"4 \u062f\u0642\u0627\u0626\u0642"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/dev95.site\/building-better-views-part-i\/#article","isPartOf":{"@id":"https:\/\/dev95.site\/building-better-views-part-i\/"},"author":{"name":"dev95","@id":"https:\/\/dev95.site\/#\/schema\/person\/b807805ffe2916206b04d0938bce0298"},"headline":"Building Better Views (Part I)","datePublished":"2019-12-26T00:00:00+00:00","mainEntityOfPage":{"@id":"https:\/\/dev95.site\/building-better-views-part-i\/"},"wordCount":649,"commentCount":0,"publisher":{"@id":"https:\/\/dev95.site\/#organization"},"image":{"@id":"https:\/\/dev95.site\/building-better-views-part-i\/#primaryimage"},"thumbnailUrl":"https:\/\/fabisevi.ch\/static\/0f600b07895848c61817aa8345f754af\/587b0\/view_data_diagram.png","articleSection":["Posts"],"inLanguage":"ar","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/dev95.site\/building-better-views-part-i\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/dev95.site\/building-better-views-part-i\/","url":"https:\/\/dev95.site\/building-better-views-part-i\/","name":"Building Better Views (Part I) - Dev95","isPartOf":{"@id":"https:\/\/dev95.site\/#website"},"primaryImageOfPage":{"@id":"https:\/\/dev95.site\/building-better-views-part-i\/#primaryimage"},"image":{"@id":"https:\/\/dev95.site\/building-better-views-part-i\/#primaryimage"},"thumbnailUrl":"https:\/\/fabisevi.ch\/static\/0f600b07895848c61817aa8345f754af\/587b0\/view_data_diagram.png","datePublished":"2019-12-26T00:00:00+00:00","breadcrumb":{"@id":"https:\/\/dev95.site\/building-better-views-part-i\/#breadcrumb"},"inLanguage":"ar","potentialAction":[{"@type":"ReadAction","target":["https:\/\/dev95.site\/building-better-views-part-i\/"]}]},{"@type":"ImageObject","inLanguage":"ar","@id":"https:\/\/dev95.site\/building-better-views-part-i\/#primaryimage","url":"https:\/\/fabisevi.ch\/static\/0f600b07895848c61817aa8345f754af\/587b0\/view_data_diagram.png","contentUrl":"https:\/\/fabisevi.ch\/static\/0f600b07895848c61817aa8345f754af\/587b0\/view_data_diagram.png"},{"@type":"BreadcrumbList","@id":"https:\/\/dev95.site\/building-better-views-part-i\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/dev95.site\/"},{"@type":"ListItem","position":2,"name":"Building Better Views (Part I)"}]},{"@type":"WebSite","@id":"https:\/\/dev95.site\/#website","url":"https:\/\/dev95.site\/","name":"Dev95","description":"\u0645\u0646\u0635\u062a\u0643 \u0627\u0644\u0631\u0642\u0645\u064a\u0629 \u0627\u0644\u0634\u0627\u0645\u0644\u0629 \u0644\u0644\u0645\u0639\u0631\u0641\u0629 \u0648\u0627\u0644\u062e\u062f\u0645\u0627\u062a \u0648\u0627\u0644\u0623\u062f\u0648\u0627\u062a \u0648\u0627\u0644\u062a\u0631\u0641\u064a\u0647.","publisher":{"@id":"https:\/\/dev95.site\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/dev95.site\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"ar"},{"@type":"Organization","@id":"https:\/\/dev95.site\/#organization","name":"Dev95","url":"https:\/\/dev95.site\/","logo":{"@type":"ImageObject","inLanguage":"ar","@id":"https:\/\/dev95.site\/#\/schema\/logo\/image\/","url":"https:\/\/i0.wp.com\/dev95.site\/wp-content\/uploads\/2026\/07\/rbrrbr-6.png?fit=512%2C512&ssl=1","contentUrl":"https:\/\/i0.wp.com\/dev95.site\/wp-content\/uploads\/2026\/07\/rbrrbr-6.png?fit=512%2C512&ssl=1","width":512,"height":512,"caption":"Dev95"},"image":{"@id":"https:\/\/dev95.site\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/dev95.site\/#\/schema\/person\/b807805ffe2916206b04d0938bce0298","name":"dev95","image":{"@type":"ImageObject","inLanguage":"ar","@id":"https:\/\/secure.gravatar.com\/avatar\/a70a73d950838b20cd80d7ebdc955737e802e8cd896044c5473b32b946c0662a?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/a70a73d950838b20cd80d7ebdc955737e802e8cd896044c5473b32b946c0662a?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/a70a73d950838b20cd80d7ebdc955737e802e8cd896044c5473b32b946c0662a?s=96&d=mm&r=g","caption":"dev95"},"url":"https:\/\/dev95.site\/ar\/author\/mohammad\/"}]}},"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/dev95.site\/ar\/wp-json\/wp\/v2\/posts\/10548","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dev95.site\/ar\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dev95.site\/ar\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dev95.site\/ar\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/dev95.site\/ar\/wp-json\/wp\/v2\/comments?post=10548"}],"version-history":[{"count":0,"href":"https:\/\/dev95.site\/ar\/wp-json\/wp\/v2\/posts\/10548\/revisions"}],"wp:attachment":[{"href":"https:\/\/dev95.site\/ar\/wp-json\/wp\/v2\/media?parent=10548"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dev95.site\/ar\/wp-json\/wp\/v2\/categories?post=10548"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dev95.site\/ar\/wp-json\/wp\/v2\/tags?post=10548"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}