How we made blazing fast articles in our mobile application

Our mobile application has been available to readers for more than 8 years. The first version was created in 2010. It was the year when Android 1.6 and iOS 4.0 were popular in Slovakia. And it was one of the first news apps in Slovakia.

Fisrt version of our iOS application.

Written by Michal Hájek

At that time we created a simple, but not very “revolutionary”, article-display system. This system has lived with us until today. Very long 10 years. We’ve invested a lot of time and energy in improving the web version of the articles, but we’ve forgotten about the app. Everything changed a few months ago (2018). And here comes our story.

Historical background of articles

When we first decided to create articles for mobile apps, we had two options.

  1. Render the articles with native components the system offered us.
  2. Create optimized websites and use webview.

For good reasons we chose second option: create optimized websites and use webview. The content we have had in the articles is very varied (many social embeds like facebook, twitter, instagram, many third party iframes, etc.).

At that time we did not have a lot of options to solve it reasonably and we did not have so much experience, so we saw the webview as a good option.

You have all html and css available. Whatever you think, you can make it as simple as the web. When you want to change or add something, it is very quick and simple.

Changes can be made by the frontend guys, so it is not necessary to use a mobile developer. If you change anything, you do not need to issue a new version of the app.

These were some very strong and reasonable arguments that helped us choose such a solution.

Opening an article

Today I would like to say that this decision was not entirely reasonable. The system appeared to be “the best in the world”, but several problems have recently begun to occur.

The biggest issue was the response time of the articles. It took a long time before the article opened and the user could read it.

In the App Store, a large number of complaints have begun to appear.

“Poorly annoyingly cracking pages, apps like this don't have a place in 2018.”
“The speed of this app is incredibly slow. I have to wait minutes to load some articles.”

“Its not working properly. Freezing.”

It usually happened that opening an article took 10 seconds. An even bigger issue arose when a push notification about something important (breaking news) appeared on the screens of the users. Everyone opened the push notification. That did not go well.

For example, the murder of a Slovak journalist. At that time, the loading time of the article was twice as big. We needed to change this. But first, we decided to optimize the webview.

We’ve done a very large article refactor — optimized assets, we started to load asynchronously many components, lazy load of pictures and ads, did everything we could, but the result was still not ideal. No satisfaction on the users end. We kept getting negative feedback. As if we did nothing.

Article loading take still almost 5 seconds.

Finally, we came to the decision to get rid of webview articles and I think it was the best decision.

We may have lost some of the benefits it offered us, but the vision of fast articles was significantly greater.

We’ll do everything native

So, after 8 years, we thought back to 2010, when deciding first time how to render the articles in the app. Still, after all of the abovementioned facts, it was not an easy decision. And there was only one to make this time.

At first, we did not know how it would go and so it was decided this would be an experiment, a beta version.

First, we’ve gotten rid of all the unnecessary parts of the articles. Only clear text with images were left. Next, we added videos.

The question remained: How to render this article only with cocoa touch uikit components? There was uilabel or uitextview for texts, uiimageview for pictures, etc. But how to put it all together?

Everything is a component

I’m a big fan of React, so make all elements of articles as components was a winner solution for me. The problem was to choose the right solution for structured data and these components.

We were inspired by the storyblok, where all content are json. Article export looks like this:

{“story”:{“name”:”landing page”,”created_at”:”2018–03–12T23:05:35.751Z”,”published_at”:”2018–08–24T06:55:57.622Z”,”alternates”:[],”id”:88299,”uuid”:”fd578ab5–9941–4280-bf90-d84349b92266",”content”:{“_uid”:”68f09850–16db-47cb-9b6c-a1eea9722059",”body”:[{“_uid”:”05d43f20-cb66–4fcd-ac7d-f9d9fc3ed718",”headline”:”Yeah”,”component”:”teaser”},{“_uid”:”a6652c4a-82cd-4a26-a85f-f3a3f828ca65",”body”:”Sem by prislo daco”,”link”:{“id”:””,”url”:”https://www.sme.sk","linktype":"url","fieldtype":"multilink","cached_url":"https://www.sme.sk"},"title":"Super video”,”component”:”video”}],”component”:”page”},”slug”:”plainjs-demo”,”full_slug”:”plainjs-demo”,”sort_by_date”:null,”position”:-72860,”tag_list”:[],”is_startpage”:false,”parent_id”:0,”meta_data”:null,”group_id”:”bb9b750a-03be-4941–8083–4839d5ced1a4"}}

This is great structured data, but it was a little difficult for us to implement it. So we made a compromise, chose a “hybrid” of json components and plain text. Our article components looks like this:

{"context":"ArtemisSchemev1","type":"image","params":{"src":"https://url_to_image","title":"Image title"}}

These components are directly inserted into the text of the article.

Hello mr. Separator

The first finished version of the article’s export looked like this (beware, Slovak language follows):

BRATISLAVA. Srdce funguje ako veľká pumpa. Bije, pumpuje krv a zabezpečuje, že telo dostane potrebnú energiu a kyslík. Ako sa krv pohybuje telom, tlačí proti stenám ciev - túto silu nazývame krvný tlak. Ak je táto sila príliš veľká, máte vysoký krvný tlak, čo značne namáha nielen krvné cievy, ale aj srdce. Vysoký krvný tlak však zvyčajne nemá úplne zjavné príznaky a nemusíte ho cítiť. Najlepšie ho odhalíte meraním. Ak lekár zistí, že máte zvýšený tlak, odporučí vám zrejme zmenu životného štýlu. V rámci nej vám možno povie, aby ste začali jesť viac čokolády a zapili ju zeleným čajom či červeným vínom. Všetky tieto pochutiny sú totiž zdrojom epikatechínu - látky, ktorá dokáže nárast krvného tlaku spomaliť. __{"context":"ArtemisSchemev1","type":"image","params":{"src":"https://url_to_image","title":"Image title"}}__Naznačuje to experiment študenta Univerzity Komenského v Bratislave (UK) Štefana Lukáča v spolupráci s Ústavom normálnej a patologickej fyziológie Slovenskej akadémie vied (SAV). Naznačuje to experiment študenta Univerzity Komenského v Bratislave (UK) Štefana Lukáča v spolupráci s Ústavom normálnej a patologickej fyziológie Slovenskej akadémie vied (SAV). Naznačuje to experiment študenta Univerzity Komenského v Bratislave (UK) Štefana Lukáča v spolupráci s Ústavom normálnej a patologickej fyziológie Slovenskej akadémie vied (SAV).

The app splits chunks of text by separators (__) and replaces json components with their alternatives directly in the application.

Another problem was there were articles in which there were inserted URL addresses (mainly hungarian URLs), which contained this separator directly in the URL. Some articles have been broken.

We had to choose another separator. There was a lot of ideas, but the winner was: __|||__. We call him Mr. Separator :-)

The final export looks like this:

BRATISLAVA. Srdce funguje ako veľká pumpa. Bije, pumpuje krv a zabezpečuje, že telo dostane potrebnú energiu a kyslík. Ako sa krv pohybuje telom, tlačí proti stenám ciev - túto silu nazývame krvný tlak. Ak je táto sila príliš veľká, máte vysoký krvný tlak, čo značne namáha nielen krvné cievy, ale aj srdce. Vysoký krvný tlak však zvyčajne nemá úplne zjavné príznaky a nemusíte ho cítiť. Najlepšie ho odhalíte meraním. Ak lekár zistí, že máte zvýšený tlak, odporučí vám zrejme zmenu životného štýlu. V rámci nej vám možno povie, aby ste začali jesť viac čokolády a zapili ju zeleným čajom či červeným vínom. Všetky tieto pochutiny sú totiž zdrojom epikatechínu - látky, ktorá dokáže nárast krvného tlaku spomaliť. __|||__{"context":"ArtemisSchemev1","type":"image","params":{"src":"https://url_to_image","title":"Image title"}}__|||__Naznačuje to experiment študenta Univerzity Komenského v Bratislave (UK) Štefana Lukáča v spolupráci s Ústavom normálnej a patologickej fyziológie Slovenskej akadémie vied (SAV). Naznačuje to experiment študenta Univerzity Komenského v Bratislave (UK) Štefana Lukáča v spolupráci s Ústavom normálnej a patologickej fyziológie Slovenskej akadémie vied (SAV). Naznačuje to experiment študenta Univerzity Komenského v Bratislave (UK) Štefana Lukáča v spolupráci s Ústavom normálnej a patologickej fyziológie Slovenskej akadémie vied (SAV).

We had finished the server side of the articles. Now was the time for the app.

How to render an article in app?

First step was easy. Download content and show this content in uitextview. Then find json components and replace them with native components in application.

In the app we created all of the article components. When we created them we have found problems with design.

Constraints in iOS storyboard are great and I love them, but it wasn’t so flexible in this case.

We decided to use one super great library: FlexLayout. This library is almost the same as the html / css flexbox. You can do everything almost the same. Example:

rootContainer.flex.direction(.column).padding(12).define { (flex) in

flex.addItem().direction(.row).define { (flex) in
flex.addItem(imageView).width(100)
    flex.addItem().direction(.column).grow(1).define { (flex) in

flex.addItem(segmentedControl).grow(1)
flex.addItem(label)
}
}
flex.addItem().height(1).marginTop(12)
flex.addItem(bottomLabel).marginTop(12)
}

Another problem was to solve the html formatting. There were many elements in the articles: “<b>, <ul>, <u>, <strike>, <a>, etc.”

We needed to format these elements same as we used webview. Someone would say, just use NSAttributedString. I swear I tried, but it was quite complicated.

Luckily, I found another great library that solved it all. If someone wants to format NSAttributedString and does not want to go crazy, I recommend: SwiftRichString. With this library you can write something very similar to css and it is beautiful :-). A little demonstration:

let style = Style {
$0.font = SystemFonts.AmericanTypewriter.font(size: 25)
$0.color = "#0433FF"
$0.underline = (.patternDot, .red)
$0.alignment = .center
}
let attributedText = "Hello World!".set(style: style)

A beautiful solution that made it very quick to format all the elements in the article. And so we had the whole article composed.

Performance issues and some experiments

No solution in the world is perfect and immortal, and it is also an example of this. In larger articles, small problems with performance and increased memory consumption began to appear.

So we tried to make an experimental solution and here comes the Metal to the scene.

We’ve created some components of the article with Metal and performance improved dramatically. I still do not know if metal is a good way, it’s just an experiment. We will see in the future. The result of all this is (blazingly fast article rendering):

New articles are opening almost immediately

This is the first version of our new articles. We are not finished with the development, we are working on it all the time and trying to improve it to give our users the best possible experience.

We are already preparing new components like: social embeds and podcast players (yes, podcasts are big in Slovakia). And I am personally looking forward to new challenges.


Michal Hájek is a mobile apps developer. He studied management and has been developing mobile apps for years, including the one for SME.sk.