Non-selectable UITextViews and URL interactions

:  ~ 1 min read

Say we have some HTML content we want to display in a UITextView:

if let stringData = string.data(using: .utf16),
	let attributedString = try? NSAttributedString(
		data: stringData,
		options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType],
		documentAttributes: nil) {
	attributedText = attributedString
}
else {
	attributedText = nil
}

For added complexity, let's assume the UITextView is inside a UIScrollView, meaning we'll most likely want the it to be non-editable, non-selectable and, for our case, non-scrollable as well. And here comes the tricky part: if we set its isSelectab […]


Continue reading →

Naming init parameters

:  ~ 45 sec read

I used to name them by the type of the parameters passed in, for example:

let dictionary = ["name": "Sneakers", "price": "40"]
let product = Product(dictionary: dictionary)
let viewModel = ProductViewModel(product: product)

But lately, I've been using a more Swifty approach, by having an external name of from or with:

let dictionary = ["name": "Sneakers", "price": "40"]
let product = Product(from: dictionary)
let viewModel = ProductViewModel(with: product)

How do I pick between the two? I go with the following approach:

 […]
Continue reading →

Naming init parameters

:  ~ 45 sec read

I used to name them by the type of the parameters passed in, for example:

let dictionary = ["name": "Sneakers", "price": "40"]
let product = Product(dictionary: dictionary)
let viewModel = ProductViewModel(product: product)

But lately, I've been using a more Swifty approach, by having an external name of from or with:

let dictionary = ["name": "Sneakers", "price": "40"]
let product = Product(from: dictionary)
let viewModel = ProductViewModel(with: product)

How do I pick between the two? I go with the following approach:

 […]
Continue reading →

[SSS] Creating a sitemap

:  ~ 2 min read

Sitemaps are used by search engines to know what pages to crawl; they're basically a list of all the URLs available on a website. Last time we saw how to manually create an RSS feed by manually creating an XML document, and a sitemap is also just an XML document.

First, let's add the route to our droplet:

func addRoutes() -> Droplet {
	get("/sitemap.xml", handler: SitemapController.create)
	// [...]
}

As we saw in the previous post, we need a controller that has a method with the same signature as the handler:

struct SitemapController {

	static func create(with request: Request) throws -> Respon […]

Continue reading →

[SSS] Creating an RSS feed

:  ~ 1 min read

Back when the blog was written in Ruby, I wrote that I eventually went ahead and implemented an RSS feed, and that it was much easier than expected. Turns out I didn't even need a library to do it, it's only a matter of creating an XML document.

Sure, it might be prettier to assign properties (e.g rss.item.content = "content here") versus creating the document manually (e.g xml += <content>content here</content>), but with proper formatting, the latter can look pretty great too. Besides, printing the document, or looking at the source in a browser will be easier to track / spot bugs.

Let's start wit […]


Continue reading →

[SSS] Displaying posts and extending Queries

:  ~ 5 min read

This is a bit tricky, since my routes for posts and pages are the same, and I differentiate between the two if I can create an Int out of the lastPathComponent. I know it's not the best approach, but since URLs should be permanent, I never moved to a /page/x structure. I also kind of dislike that structure ¯\-(ツ)-/¯.

In the first post in this series, I briefly presented the Droplet extension, with a very basic addRoutes method, just to present the methods in the extension itself. Let's give it a few routes:

extension Droplet {

	func addRoutes() -> Droplet {
		get("/feed", handler: FeedController […]

Continue reading →

[SSS] Displaying posts and extending Queries

:  ~ 5 min read

This is a bit tricky, since my routes for posts and pages are the same, and I differentiate between the two if I can create an Int out of the lastPathComponent. I know it's not the best approach, but since URLs should be permanent, I never moved to a /page/x structure. I also kind of dislike that structure ¯-(ツ)-/¯.

In the first post in this series, I briefly presented the Droplet extension, with a very basic addRoutes method, just to present the methods in the extension itself. Let's give it a few routes:

extension Droplet {

	func addRoutes() -> Droplet {
		get("/feed", handler: FeedController. […]

Continue reading →

[SSS] PostgreSQL models

:  ~ 3 min read

Let's start by defining our Post model:

struct Post {

	let title: String
	var rawBody: String { // The original, markdown body.
		didSet {
			// For updating body, truncatedBody and readingTime automatically.
			// didSet doesn't get called on init too, sadly.
		}
	}
	fileprivate(set) var body: String // The html body.
	fileprivate(set) var truncatedBody: String // The html body, truncated to x chars.
	fileprivate(set) var readingTime: String
	let datetime: String // The date, in yyyy-MM-dd-HHmm format.
	let link: String // The link, created from the title, in post-title format.
	let date: St […]

Continue reading →

[SSS] Setting the project up

:  ~ 2 min read

The first post in the Server Side Swift series will be about initializing the project, its structure, and configuring your Droplet. Running the vapor xcode -y command (although I always run swift build first) will download dependencies, build them, configure an Xcode project, and you will end up with a structure like this:

___ Config
   |___ secrets (optional) - This should be in your .gitignore.
   |___ production (optional)
   |_ app.json
   |_ servers.json
___ Localization - Translation files.
   |_ xx-YY.json
___ Packages - This is where Vapor installs your packages, and links them in Xcod […]

Continue reading →

Server side Swift with Vapor

I finally decided to migrate the blog from Node.js to Swift, and that's what I've been working on for the past weeks. It's been fun, and in the upcoming posts I will be writing about how it went. I will prefix them with [SSS], just like I did with [NJS]. The repo can be found here.

Hope you'll enjoy them as much as I did!