Should I use struct in Swift?

“Should I use struct or class?” is a common question of Swift developer. There may be something you also hear over and over again like: struct is value semantic, struct is faster. Is it really as it being said or is there any thing hidden behind? Let’s find out!

Note: For better format post, please check out Should I use struct in Swift?

Read More…

Understanding UIView’s transform property (final)

In previous part, we talked about 4 properties of UIView and relationships between them. This part we cover operations with transform and how to persist UIView information. Let’s go!

transform operations

transform is type of CGAffineTransform and it represents a matrix used for affine transformation. Speaking of the matrix and and affine transformation, it is beyond context of this article, but if you wonder and want to learn more, this wiki would be a good start.

In brief, transform includes 6 matter values a, b, c, d, x and y as the figure below.

a and d are for scale, x and y are for translation and a, b, c and d are for rotation. However, usually, we use only scale and rotation of transform as for translation, we can simply use center property to position a view in its superview.

When transform is used for only one transformation, it is straightforward to extract that information, e.g. factor of scale or angle of rotation. In most of cases, however, we use combination of scale and rotation, that makes transformation extraction more tangled. Thanks to mathematics, we already have equations for this and only need to convert to code.


Extract

Right below is snippet for scale extraction

func scaleOf(transform: CGAffineTransform) -> CGPoint {
let xScale = sqrt(transform.a * transform.a + transform.c * transform.c)
let yScale = sqrt(transform.b * transform.b + transform.d * transform.d)

return CGPoint(x: xScale, y: yScale)
}

and for rotation.

func rotationOf(transform: CGAffineTransform) -> CGFloat {
return CGFloat(atan2(transform.b, transform.a))
}

Restore

In reverse, CoreGraphics provides handy functions to create CGAffineTransform from transformation information.

view.transform = CGAffineTransformMakeRotation(angle_in_radian) // Create CGAffineTransform of rotation transformation

view.transform = CGAffineTransformMakeScale(xScale, yScale) // Create CGAffineTransform of scale transformation

Because order of transformation matters, in case of combination of scale and rotation, we should persist the whole transform, i.e., a, b, c, d, x and y values, and use it to restore itself.

view.transform = CGAffineTransform(a: a, b: b, c: c, d: d, tx: x, ty: y);

Persistence

When comes with UIView information persistence, especially with transform is applied, note following things:

  • frame is invalid so we shouldn’t use it to position or measure view.
  • Though frame is invalid, there is way to calculate actual values and use them for positioning or sizing of view.
  • center is recommended to position view.
  • bounds.size is recommended to measure view.

So what information we need to persist? They are position in superview, size and transformation. With transformation, we can persist transform as a whole or individual one.

Position

The best way is to persist center, as center is independent of transform, it is safe to position view regardless of transform.

let persistedCenter = view.center

However, in some scenarios, frame.origin may be useful, then we need calculation on restoration to convert frame.origin back to center. It will be there later.

let persistedPosition = frame.origin

Size

Both bounds.size and frame.size cannot be used for size persistence, because they do not reflect correct view’s size. bounds.size is original value before transformation. And frame.size is size of boundary view, not actual view.

So how? The answer is to use bounds.size and scale transformation and it is pretty simple.

let scale = scaleOf(view.transform)
let persistedSize = CGSize(width: view.bounds.size.width * scale.x, height: view.bounds.size.height * scale.y)

If we count actual view’s size in persistence, transform we persist should contain only rotation transformation. This is due of restore phrase later. Otherwise, restoration will get unnecessary calculation, now or later is of your choice. Then I choose now and it also makes more sense to persist real view’s size than its original one.

Transformation

How to persist position and size affects how to do with transformation, actually, only size does. As stated right above, if we persist actual view’s size, rotation is the only thing we need for transformation.

let persistedRotation = rotationOf(view.transform)

How about original view’s size? So we have to persist the whole transform by using its values.

let a = view.transform.a
let b = view.transform.b
let c = view.transform.c
let d = view.transform.d

With these values, it is easy to restore transform as talked above.

Restore

Make assumption that we are persisting actual view’s size, its rotation and center, now it is time to restore the view from that.

let view = UIView(frame: CGRect(x: 0, y: 0, width: persistedSize.width, height: persistedSize.height))
view.transform = CGAffineTransformMakeRotation(persistedRotation)
view.center = persistedCenter

How about frame.origin for position? Here we are.

let view = UIView(frame: CGRect(x: 0, y: 0, width: persistedSize.width, height: persistedSize.height))
view.transform = CGAffineTransformMakeRotation(persistedRotation)
view.center = CGPoint(x: persistedPosition.x + view.frame.size.width / 2, y: persistedPosition.y + view.frame.size.height / 2)

Conclusion

There are still many more to talk about UIView, however, with this article, transform property is not scary anymore, huh? From here, we can keep learning layer.anchorPoint which is also relevant to transform, animation with transform and other 3 properties, etc. Happy learning!

Understanding UIView’s transform property (part 1)

Working with transform property of UIView might be frustrated at the first time. Confusion of using transform leads to difficulty in controlling UIView as well as persisting UIView information. This article helps demystify this.

Basics

Before going clarify transform property and how it works, let’s remind some basics. With a bunch of properties and methods in UIView, there are only four that we need in context of this article and the rest of it focuses only these four properties to try to explain how transform works.

frame
The frame rectangle, which describes the view’s location and size in its superview’s coordinate system.
bounds
The bounds rectangle, which describes the view’s location and size in its own coordinate system.
center
The center of the frame, i.e., it is location of the view’s center point in its superview’s coordinate system.
transform
Specifies the transform applied to the receiver, relative to the center of its bounds.

WARNING
If this property is not the identity transform, the value of the frame property is undefined and therefore should be ignored.

These four properties have binding of each other, changes on one cause changes mostly on others. Simplest, for example, changes on center modify frame, and vise versa. We talk more about these relationships right below.


Relationships

frame changes

When frame changes, obviously, it causes change of bounds and center but remains transform. Changes on frame.origin and frame.size result in changes on center and bounds.size respectively.

frame.origin changes center
frame.size changes bounds.size

bounds changes

As bounds.size changes, the whole frame changes, I mean both frame.origin and frame.size. The reason is this change is relative to the view’s center point, the center point keeps the same while 4 corners move inward or outward depending on decreasing or increasing the size. System now reflects these changes to the view’s superview’s coordinate by change the view’s frame.

<img src="https://github.com/ninjaprox/Assets/raw/master/Figure%201.png&quot; alt="bounds.size changes” />

bounds.size changes frame.origin and frame.size

frame.size is always equal to bounds.size on the other hand.

How about bounds.origin? It does not affect frame at all. It just shifts the view’s content, like the way you see in UIScrollView.

center changes

Because center and frame are both determined in superview ‘s coordinate system, i.e., they are in the same coordinate system, no wonder that they affect each other.

center changes frame.origin

transform changes

Now here is the most confusing of 4 properties. Don’t panic. It is purely mathematics. What, mathematics? It is even more scary. No, even if you are not math genius, understanding it must not be hard.

The idea is that transform is, simplified-explanation, a calculation being applied to a view to convert every single point inside the view to new position in the same coordinate system of the view’s superview. Keeping superview’s coordinate system untouched helps diminish effort to work with other views that do not use transform, i.e., transform is identity.

transform
input [some calculations happen here]=> output

As superview needs a straight rectangle to determine position and size of its child view, in case child view does not have one, e.g. it is rotated, superview uses a boundary to do this job. The boundary is the smallest straight rectangle that encloses completely the view.

View's boundary

Scale

Now let’s scale up and down a view. Recall the earlier explanation of transform, when scaling a view, in fact transform does not change real view’s size but only do conversion the size to new size in view’s superview and display it. This conversion, easy to guess, has effect on view’s frame.

Scale

transform changes frame

What if we change frame after applied scale? Good question. Remember frame.size is always equal to bounds.size said earlier? New frame.size comes from old frame.size, actually comes from bounds.size. On forward way, bounds.size is as input and new frame.size is as output. And frame.size is as input and bounds.size is as output in reverse.

It is supposed to be but it is not unfortunately. As warning in transform, frame should be ignored. In fact, we still can use it to new frame value after scaled, as well as frame of boundary being mentioned right below, but it is not recommended to set value, even with frame.origin.

Therefore the answer is shouldn’t do.

Rotation

Now it is time for rotation. As in earlier figure, when a view is rotated, it does not longer have a straight rectangle to represent in its superview. This comes to superview needs a boundary to position and measure the view. The view’s frame now is actually the boundary’s frame and it does not literally reflect view’s position and size anymore.

transform changes frame

Combination

In combination of scale and rotation, the same principle is applied.

 

In this part, we have better idea of 4 properties and their relationship. In the next one, we will talk more about transform, how to use it and applications, especially on persistence.

Tutorial: Create ruler using Flexbox layout

Introduction

Flexbox coming with CCS3 is an useful, handy way to do layouts in CSS. Learning using flexbox is pretty simple and you can find out a bunch of resource to learn this. In this post, I give a tutorial to apply flexbox to create ruler with pure HTML and CSS.

Plan ahead

Before getting started, we need to imagine and break down components needed to form a ruler. There are some you may think of:

  • Ruler board
  • Major sticks
  • Minor sticks
  • Value for major sticks

For example, we are going to create one like this:

Ruler

We have 11 major sticks that go with 11 corresponding values. For each segment between 2 adjacent major sticks, there are 9 minor sticks or you can think there are actually 11, but the first and last one are hidden behind the major sticks.

Read More…

Access ngModel value in directive

Angular built-in directives are useful and sufficient for most of basic use. However, to leverage the power provided by the framework, writing custom directive is inevitable. In this post, I will introduce ways to access ngModel in directive to create more robust components in application.

Before going ahead, just revise knowledge we have. This is non-trivial to understand why an approach working in this case but not in another one.

Understand ngModel

First of all, we need to remind how to use ngModel and what happening when using it. Normally, ngModel will be added into input tag and followed by an expression that indicates property in scope.

<input type='text' ng-model='myModel'>

In above example, myModel is the expression that Angular will evaluate, then bind input tag to this property in the scope. If myModel is not found in the scope, Angular will implicitly create and add into the scope.

Understand matching attributes

Matching attributes is the way to pass data to directive using attributes in the element. For data, there are two ways: @ and =. Their explanation can be simplify as:
* @: mono-directional binding, interpolation.
* =: bi-directional binding, parse.

What? Don’t worry, I will explain latter via examples, it is easier to understand.

Great, till now we have enough foundation to continue. There, however, is one more thing we need, that is scope types in directive.

As we know already, there are three types of scope in directive: no scope, inherited scope from parent scope and ultimately isolated scope. If you are not familiar with this, reference Angular’s guide first. Why do we need to concern scope of directive? It will affect how we access ngModel value in directive. Let’s go through each type and see which ways we can use.

No scope at all

Directive uses its parent’s scope instead of creating a new one for itself. Thus, it can see all scope properties, of course, model value as well. Because of this, the most straightforward way is to directly access scope properties.

// No scope
app.directive('d1', function() {
  return {
    restrict: 'E',
    link: function($scope, $element, $attr) {
      angular.element($element).append("Hello ");
      angular.element($element).append($scope[$attr.ngModel]);
    }
  };
});
<d1 ng-model='hello'></d1>

Inherited scope from parent

This is the same as before, no difference.

// Inherited scope
app.directive('d2', function() {
  return {
    restrict: 'E',
    scope: true,
    link: function($scope, $element, $attr) {
      angular.element($element).append("Hello ");
      angular.element($element).append($scope[$attr.ngModel]);
    }
  };
});

Isolated scope

Unlike previous cases, we can’t get model value directly from neither parent scope nor directive’s. This is because the scope is completely isolated from the rest of the world, it is the only one and stands alone. What can we do in this case?

// Isolated scope
app.directive('d3', function() {
  return {
    restrict: 'E',
    scope: {
      modelValue: '=ngModel'
    },
    link: function($scope, $element, $attr) {
      angular.element($element).append("Hello ");
      angular.element($element).append($scope.modelValue);
    }
  };
});
<d3 ng-model='hello'></d3>

By using matching attributes, we take advantage of Angular expression evaluation. What that means? Angular will evaluate hello, then bind hello property in the scope to which the element belongs to modelValue property in the isolated scope. From now, every change in hello or modelValue will be updated and reflect each other.

Note: We must use = instead of @. Why? As said before, @ is for mono-directional binding, interpolation. See the following example:

// Isolated scope
app.directive('d4', function() {
  return {
    restrict: 'E',
    scope: {
      modelValue: '@ngModel'
    },
    link: function($scope, $element, $attr) {
      angular.element($element).append("Hello ");
      angular.element($element).append($scope.modelValue);
    }
  };
});
<d4 ng-model='hello'></d4>

If using @, instead of parsing hello, it will be interpolated. Therefore $scope.modelValue will be hello literally, not the value of hello property as we expect.

Here is all of above examples.

Conclusion

If directive doesn’t own scope or inherits from its parent scope, just access via scope. Ultimately we need workaround in isolated scope by using matching attributes. And don’t forget to use = instead of @.

Create custom view from XIB

Firstly, this is not a brand new topic. Just google “view from xib”, you can see over million of results. The common solution you will get must be:

UIView *view = [[[NSBundle mainBundle] loadNibNamed:@"xib name" owner:self options:nil] objectAtIndex:0];

Then just add the view onto wherever you need and done. It is simple and fast enough. So why am I still writing this?

Read More…

Client satisfaction and Flappy Bird

Yesterday, my boss shared his secret on managing a lot projects at the same time, but still keeping all clients satisfactory. That sounds like miracle huh? At first I thought that. However, after his talk, I found myself an interesting link with Flappy Bird.

Let’s imagine client as the bird in Flappy Bird and their expectation from us as the position of the bird in game. At the beginning, the bird will fall down if we do nothing – in this case is tapping screen. Analogically, when project just started, client have no idea about us, even maybe they do not trust us. Day by day, their expectation will go down and down. That is the first tough period of project. So what can we do? Go back to the game, what do you do? Just tapping huh, easy enough? Yes, it is easy but it works. Tapping and tapping keeps the bird up and passing the first pipe. The same way also works with client. Clarifying specifications, asking for materials,… all such those things like taps, are building client’s trust and pushing their satisfaction to the top. It is necessary, because over time satisfaction will be down again.

Like the game, after passing the first pipe, the bird again falls down. We need some more taps to pass following pipes. Likewise, during project, small actions are needed to revive client’s satisfactory. They may be asking issues, updating on Trello, weekly build,… just little things but having great power.

However, different from Flappy Bird, our project has an end point – means completing and delivering the project, not hitting pipes like the bird on the game. This is an another challenge in project. All frustrating things often happen here. One solution is to go over in advance this period when starting the project to figure out stuffs which needs to be prepared. Therefore, we can avoid breaking plan or overtime working or annoying things. By that, we can gain 99.9% satisfaction from our client.

In summary, just keep in mind a simple principle like playing Flappy Bird. Client’s satisfaction will go down and up by time. Our mission is to keep it up when it is down and to deliver our client the best result.

Flappy Bird, cái quái gì thế này???

Cảnh báo: bài này chỉ để bày tỏ cảm suy nghĩ, cảm xúc khi nghe đến trò chơi này và lần đầu tiên chơi nó. Không có một tí review, phân tích, đánh giá gì hết tẹo.

Read More…

One Direction – What Makes You Beautiful (5 Piano Guys, 1 piano) – ThePianoGuys

Like the way guys do this, creativity, combination, technique,… everything is perfect. A beautiful clip to end a day.