1 2 3 |
|
In order to compose things nicely, you put the seasons into a struct:
1 2 3 |
|
The following JSON comes from the server, it gets decoded, everything works well:
1 2 |
|
The application gets released. Time passes, winter comes and the app gets updated available seasons from the backend:
1
|
|
What happens now? Your functionality breaks.
Since the app can’t understand Season.winter
, no seasons get decoded. You receive a lot of bug reports, and your users are not happy ☹️
If only there was something we could do to prevent this from happening..
This seems like a nice use case for property wrappers!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
This way, we simply add @IgnoreUnknown
before our available seasons and voilà! After that, the available
array simply skips the values it cannot understand 🚀
1 2 3 4 |
|
Property Wrappers come with a lot of other great use cases. Please see Properties in Apple documentation for more details 🙂
Hope this blogpost was helpful, thanks for reading!
]]>One way to model it is by using the following data structure:
1 2 3 4 5 |
|
One issue we are going to come about is that our model is strict, it needs all the values at once, whereas users will supply each value at a time. First they will type in their name, then their age, and so on.
Wrapping up the fields in Optional
, may loosen its strictness.
1 2 3 4 5 |
|
Our flow code might look like:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
However, now we need to guard
against any nil
values if we want to use them (for example, to make a network request).
1 2 3 4 5 6 7 |
|
From a domain perspective, that return
doesn’t make any sense.
One could argue that it’s “safe” to force unwrap in this case, or that there is already a nice approach to this problem.
One may say, “we can raise an error to the user” or “we could track it and check if users are getting stuck somehow”. But, at the end of the day, this is not a good solution because you know that when the flow ends, you have all the values.
Our model is “lying” to us. That’s not loosen, it’s just flawed.
There are several approaches to make it better, like “one model per step”:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
|
That’s better! But there is also another way of doing things that doesn’t involve duplication nor partial data structs.
Instead of breaking down our data structure, why not to break down functions?
Our FormData
initializer, when interpreted as a function, has this shape:
1
|
|
But we can break it down into plain old lambdas1, and by applying it to the initializer for our data structure:
1
|
|
This technique is called currying. What it does is, it allow us to translate the evaluation of a function that takes multiple arguments into evaluating a sequence of functions, each with a single argument.
1 2 3 4 5 |
|
The function above goes from a function that takes multiple arguments (A, B, C)
and produces a D
, to single functions, that take one argument each: (A) -> (B) -> (C)
and produces a D
, making it possible to partially apply each argument, one at the time, until it can evaluate and return the output value.
Using it in our flow, may look like the following:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
I’ve added a few type aliases
just to make it more readable.
Cleaning up them further, we’ll have:
1 2 3 |
|
If you ask me, this is much better because we didn’t have to write anything else, other than the curry
2 function itself, which can be used in other places.
And that’s it! Functions have saved the day :)
P.S: I want to thank Sean Olszewski, Gordon Fontenot, Peter Tomaselli, Henrique Morbin, Marcelo Gobetti and João Rutkoski for their awesome review.
functions take one argument and return one result.
From the book: Haskell Programming from First Principles
↩
Or just use the Curry.framework↩
1 2 3 4 5 |
|
Once the structure conforms to Codable
everything works out of the box. There’s a nice way to test those structures and make sure that everything gets the exact JSON format that we aligned with backend.
Let’s create the following protocol in the test bundle:
1 2 3 4 |
|
After that we can immediately provide an extension which conforms to that protocol in the test bundle:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Then there’s only one simple step which needs to be done in the test bundle in order to test the structure:
PersonTests.swift
:
1
|
|
That’s it! Now we can easily test the result of the serialization and deserialization :)
Example tests:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
What do you think about this method? Is there anything which could be improved in this implementation? Please let us know :)
]]>This technique is very useful when you want to abstract away third-party code (think UserDefaults
), but there are instances where this is not enough. That’s the case when working with the camera.
On iOS, to use the camera, one has to use the machinery that comes with AVFoundation
.
Although you can use protocols
to generalize the real objects, at some point, you are going to stumble upon a dilemma: the simulator doesn’t have a camera, and you can’t instantiate the framework classes making the tests (almost) impossible.
Let’s start with a very simple program that captures QR Code (I’m skipping lots of boilerplate but if you are looking for a more thorough example, here you have a great article).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
|
When the detection happens, you can compute from framework-provided values, by implementing the following method from AVCaptureMetadataOutputObjectsDelegate
. Say we want to exercise our program in a way that we ensure that the CameraOutputDelegate
methods are properly called, given what AVFoundation
provides.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
|
Waat!?
The problem here is that all of these classes are concrete, so we can’t abstract them into an interface. Also they are supposed to be created and populated at runtime, hence you can’t init
them.
Swizzle
to the rescueOne possible solution for this kind of scenario (since the framework it’s all Objective-C
…for now at least), is to use the Objective-C
runtime shenanigans to “fill this gap”.
This is only possible because in Objective-C
the method to call when a message is sent to an object is resolved at runtime.
I’m not going to lay down the nitty-gritty details about how it works, but the main idea (for the sake of this example) is to, at runtime, copy the implementation of NSObject.init
and exchange it with some new fake init
we are going to create.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
With that in hand, now we can:
private init
that will hold the implemetation of NSObject.init
.1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
|
Now, we can create a fake QR code payload in our tests and check if your implementation of AVCaptureMetadataOutputObjectsDelegate
does what you expect it to.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
|
As you can see, you can also check if your sut
handles just QR code.
You can use this technique along side with other collaborators, like AVCaptureDevice
, AVCaptureInput
and AVCaptureOutput
.
The Builder Pattern if defined as follows:
Separate the construction of a complex object from its representation so that the same construction process can create different representations.
Now, consider for a while the creation of an UIAlertView
in iOS.
1
|
|
This is a long method call, right? But really, that’s not the problem. The problem here is that our class has to conform to UIAlertViewDelegate
in order to receive the alert result. Wouldn’t be nicer to have that logic encapsulated? Well, go back and read the definition for the builder pattern, it fits like a glove, am I right?
An idea on how to wrap the builder pattern around the UIAlertView
class is as above:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
|
Now, all that is necessary to use create an alert is:
1 2 3 4 5 6 |
|
In the past, I would have used the first approach and lived with that. Of course, showing alerts to the user is a very tiny part of a real work application. But that’s preciselly where I was wrong. This kind of applicability of the builder (among all other design patterns) is what makes software components reusable.
And there are some other places where you could apply the same principle, for example NSAttributedString
or UIActionSheet
.
I hope you find that useful. Builder to the rescue!
P.S: Yes, yes I know that Apple has released UIAlertController
and deprecated both UIAlertView
and UIActionSheet
. However, the idea is pretty much the same, alothough what Apple did is Factory instead of a Builder.
@noescape
attribute. It’s a very important feature, when we want to make our code more cleaner and stricter. Using it properly at 3am will prevent many unwanted retain cycles.
While digging into release notes we can see a bunch of clever words:
A new
@noescape
attribute may be used on closure parameters to functions. This indicates that the parameter is only ever called (or passed as an @noescape parameter in a call), which means that it cannot outlive the lifetime of the call. This enables some minor performance optimizations, but more importantly disables theself.
requirement in closure arguments.
Lets analyze those smart statements and put it into code so everyone can enjoy it:
1 2 3 4 5 6 7 8 9 10 11 |
|
It can be also captured in another @noescape
closure:
1 2 3 4 5 6 7 |
|
It’s important to point out, that closures (and functions) annotated with @noescape
can only be passed as @noescape
parameters. What this mean is:
@noescape
closure
Last to mention, in the future releases this will be taken even further:
This enables control-flow-like functions to be more transparent about their behavior. In a future beta, the standard library will adopt this attribute in functions like autoreleasepool().
1 2 3 4 5 |
|
So dear developer the best is yet to come! ;]
]]>This code:
1 2 3 |
|
Will be converted into:
1 2 3 |
|
And as far this is all pretty straightforward so now having our C CoreAudio implementation we can use it in our Swift project like that:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
|
But because Swift is very strict when it comes to type checks we are no more able to pass our class to InitializeAudioSource
function, if you try to do so:
1
|
|
You will end up with this error:
And this is were the bad hacks come in. Unfotunately we need to get a “true” raw pointer to be able to pass it back to C code and to so we need this piece of code:
1 2 3 4 5 6 7 8 |
|
And that’s how you pass Swift classes and objects to C code, and you will need to do it every time you need a void or any other fancy pointer on C side.
What happens here is that we first take an Unmanaged
version of our class object this tells compiler that we are now responsible for memory management, and stops doing retain release magic under the hood for us. But still this is not enough, now we need a raw memory pointer from that unmanaged object and thats where toOpaque()
comes in. This will return an raw C pointer of our class object. This is the true void *
pointer.
COpaquePointer
is memory representation of something that cannot be represented in Swift so you should be very careful when playing with this kind of pointers. Now we just need to make it a proper type in this case UnsafeMutablePointer
with <Void>
class type. Every UnsafePointer have constructor that takes COpaquePointer
so you have to be sure you are choosing proper type when creating it as there is no type check at this point!
Hopefully on C side it’s easy to convert void pointer to proper class type, you just need to use bridge
to do so:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
I hope this will help people understand a bit more about how danger may be playing with C in Swift and vice versa. Using Unmanaged
and COpaquePointer
may lead to crashes and memory leaks, as in some cases you are again responsible for manual memory managment, you are able to get raw pointers with no type that can be casted to whatever you want and so on.
Overall this is a powerful magic you can do in Swift but as someone said: “With Great Power Comes Great Responsibility” ;)
Example usage available on github
]]>Everyone knows that building good multiplayer game is hard, multiplayer itself is hard… But here I want to show you my small proof of concept of working bluetooth low enery multiplayer game.
It can be used in any kind of game! Strategy, board, rpg, race. I built§ a small demo project to show this in details but now let’s focus on basics:
Pros:
Cons:
We have our interface class that will be used to extend functionality on both server and client logic (we use central and peripheral mode of our phone)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
|
As you can see, it’s very simple - one send and one receive method as delegate. As both recive and send arguments, we can get the command used in your game to recognize packet type and data which will come along with this command.
Now we need to implement our server and client logic, i don’t want to describe in details how to setup BluetoothLE on iPhone so insted I will highlight only important methods like receiving and sending packet on both client and server side.
KWSBluetoothLEClient
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
|
KWSBluetoothLEServer
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
|
In both cases sending and reciving is the same:
Sending:
Receive:
Thanks to that we can build our game logic like this:
Setup:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Sending data to other player:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
Reciving data:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
|
And i get some pretty promising results:
Game works smoothly, there are no lags in connection and you can play almost instantly! And of course it allows you to integrate mutliplayer in your game in few minutes.
If you are starting your journey with gamedev or iOS and plan to build simple SpriteKit game with some basic multiplayer support it may be worth considering this option.
Demo project used to present the mechanics is available as always on github
Game require at least two iPhone 5 to test and play. To start simply open game, one of the players choose server, other one client mode and bring your phone next to each another. Once you do that you should be notified about successfull connection by tone sound.
]]>Fortunately, Apple gave us a book and a couple of WWDC session (here and here) with the intent to help developers on this task.
For those who have some experience with this integration knows that casting plays an important role. So, todays hint will dig into an poor documented protocol called _ObjectiveCBridgeable
.
The documentation, which is only founded in header files says:
A Swift Array or Dictionary of types conforming to ObjectiveCBridgeable can be passed to Objective-C as an NSArray or NSDictionary, respectively. The elements of the resulting NSArray or NSDictionary will be the result of calling bridgeToObjectiveC on each element of the source container.
Ok, but there is something else you can do with that, which is very handy.
Suppose that you have this class in Objective-C:
1 2 3 4 5 6 7 8 |
|
Now you want to easily cast this class into a Swift struct. Yes, we can! All you have to do is conform to _ObjectiveCBridgeable
, like so:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
|
And voilá!
1 2 3 4 5 6 7 8 9 10 11 12 |
|
Oh, that’s so beautiful, don’t you think? :]
]]>UITraitCollection
. Trait collection object has two size classes: horizontal and vertical. Each of these classes has three possible values: compact, regular or any. The current device+orientation can be described as a combination of the sizes.
The best thing is that storyboards and nib files support these size classes. We can make layout changes directly onto them. Every view or auto-layout constraint can exist in one or several other size classes. So it is possible to support multiple devices and orientations without any code. Nevertheless there is a case, which is not covered at all. Imagine that you support only portrait mode and the designer wishes to make a difference between iPhone 5 and iPhone 6+ screen. In this case, size classes are not much helpful. However, we can leverage them in an unusual way.
UITraitEnvironment
is a protocol which provides access to trait collection. Its conformed by most of the objects in view hierarchy: UIScreen
, UIWindow
, UIViewController
, UIView
. Every child inherits the trait collection object from its parent. The trick is to override the trait collection in UIWindow
and return a custom value for iPhone 6+ device. Take a look:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
We override trait collection in UIWindow
just for iPhone 6+ model. Now we can make layout changes in storyboard directly for this model by changing size class selectors at the bottom of Interface Builder pane. Trait collection with horizontal compact class and vertical compact class is reserved for iPhone 6+.
We can install additional views and change layout constraints only for iPhone 6+.
Tell your designer about that cool hint and you will probably get some treats. The project shown above can be found on GitHub.
]]>Having an application running at 60 FPS is every programmers dream, and users delight. The worst users experience ever is a frozen and unresponsive screen. It’s a dreadful crime in mobile world nowadays. Users try to interact at any moment and according to Murphy’s law they will find all your mistakes. So, you better keep the main thread slim.
To keep things smoothly in the users interface, every single operation that’s schedule to run into the main thread can take longer than 16 milliseconds, and there’s a handy solution to get you covered. It’s a little library called Watchdog.
Watchdog is a very simple and straightforward library that logs excessive blocking on the main thread. Let’s take a look at how to use it:
1
|
|
Just instantiate it with a number of seconds that you want for Watchdog to consider that the main thread blocked. Also don’t forget to retain Watchdog somewhere or it will get released when it goes out of scope. Whenever the main thread is blocked for more than the value previously defined, it will print out logs, just like this:
1
|
|
Pretty nice debugging tool!
]]>Every time a new translation comes, it’s necessary to run the application and check for broken layouts. Take this quite simple UI.
Simple, huh?
All right, here’s what you have to do to get covered with future translations, and avoid autolayout nightmares.
Add -NSDoubleLocalizedStrings YES
to Arguments Passed On Launch
to the Run
section at your Project Schemes
.
This argument will duplicate all strings loaded using NSLocalizedString
.
What’s better then that? What about finding out unlocalized strings?
So, -NSShowNonLocalizedStrings YES
comes to rescue!
Great! Now you go and get yourself a cup of coffee while the translation team does their job :)
]]>UIMotionEffects
was first introduced in iOS 7. The WWDC session which presented this, amongst other cool things, is named Implementing Engaging UI on iOS. Nevertheless, UIMotionEffects
is still overlooked. But not today, let’s make something cool with it.
Motion effects is an easy way to react to external variations on the device’s orientation. To say, UIKit
performs UI changes whenever the user tilts the device, vertically or horizontally.
Let’s use UIInterpolatingMotionEffect
a subclass of UIMotionEffects
, with MapKit
. Notice how appealing it is.
Sweet, right?
Achieving it, is easier than you think. Just a few lines of code and you’re good to go:
1 2 3 4 5 |
|
Think of minimumRelativeValue
and maximumRelativeValue
as leading and tralling constraints, respectivily, to its superview
.
That’s why you have to create the UIView
, MKMapView
in this case, outside its superview
s bounds. Like so:
As the user tilts the device, UIInterpolatingMotionEffect
translates the fixed offset values returned by the system to the range of specified values, then UIKit
applies the translated values to any target views.
Don’t forget about this! Details matters and it’s what users love in mobile apps!
]]>1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
That’s a huge log! And I cut off the NSLayoutConstraint
part. Yet, the second last line is giving a clue in which direction to go to fix this issue. Symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints
.
All right, here’s what Xcode want’s you to do:
Honestly, that won’t help much, because basically it’ll just stop the execution and leave you up with LLDB
, alone in the dark.
But there’s a little trick you can do to enhance the preceding symbolic breakpoint.
Adding po [[UIWindow keyWindow] _autolayoutTrace]
to it (for Obj-C projects) or expr -l objc++ -O -- [[UIWindow keyWindow] _autolayoutTrace]
(for Swift projects).
Now, on console, you’ll see all the UIView
hierarchy and exactly where it has ambiguity.
1 2 3 4 5 |
|
Note that as you hit continue it’ll stop at every ambiguous layout you may have. And if that’s not enough for you to find out your autolayout issue, try changing the view’s color, who knows?
1 2 |
|
Fear no more young Padawan, make symbolic breakpoints and LLDB
work for you!
I would like to thank Porter Hoskins for pointing out the correct LLDB
command for Swift.
Besides of helpfull UserInfo object keys which give us comprehensive text information about progress of our tasks in proper language, NSProgress was supposed to provide us way of compositioning objects into trees. However, first version of class allowed this in an implicit way which does not look very clear first time you learn it.
I will try to present it to you in a short way:
1 2 3 4 5 6 |
|
When applying this approach you have to create child progress using totalUnitCount convenience constructor immediately. You also should document that you support implicit composition in a clear way.
OSX 10.11 and iOS 9.0 provides more explicit way for creating tree structure of NSProgress objects. Things are simple now:
1 2 3 |
|
There is also one more thing useful thing in process of forwarding progress through our app architecture. When any of your classes is free to attend in NSProgress family tree, simply implement following protocol:
1 2 3 |
|
This way we are able to easily track progress of tree structure of tasks and get our overall progress in an easy, object oriented way.
]]>NSDateFormatter
when it comes to parsing dates in your project. If you don’t read it yet, I will highly recommend to do it now. This time we will use Swift to make same measurements.
TL;DR:
You can use sql database function strftime
to get UNIX time from e.g.: ISO8061 date string.
Here is the magic function:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
|
We will use it to replace standard parsing method like this:
1 2 3 4 5 |
|
I did some measurements using iPhone 5S with iOS8.2 in release configuration running exactly same amount of data (One Milion strings with ISO8601 date)
And here are the results:
1 2 |
|
So using SQL to format string into date is pretty fast but acutally slower than objC version (But still at least 10time faster than regular method) So what about Swift?. Nothing really changed, overall results show faster computation but I’m using better CPU so NSDateFormatter
is still very very slow… If you like it, sample source code is available on Github
There’s a particular situation that occurs with iOS, that’s perfect for applying the LoD. Sometimes it’s needed to call method in our UIApplicationDelegate
. The common way of doing that is the following:
1 2 3 4 5 |
|
There are too many temporary objects, and presumably, there’s no reason why this class should know about AppDelegate
casting and so on.
Using the Decorator
pattern, is a way to wrap up this logic and decouple stuff.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Now the class would just call UIApplication.doSomething()
or AppDelegate.doSomething()
.
Another situation that’s a claimer for LoD is when you have chained ‘get’ statements, for example:
1
|
|
In such a case, the Metallica
class should be refactored and provide it with a mean of calling Metallica().gimmeThatWhichIDesire()
, for example:
1 2 3 4 5 6 7 8 9 |
|
Wrapping up method calls, separating concerns and decoupling classes are the spine of LoD. Some can say that objects become more complex, but one thing is for sure, your software components will be more testable, and that is a big win!
Now go ahead and follow the rule!
]]>As usual create new Run Script Phase
and insert your Bash script:
To keep this blog post short, I’ve created a simple script that checks which build configurations were used:
1 2 3 4 5 6 7 8 9 |
|
Please, take a look in every echo at note:
, warning:
and error:
prefixes. When XCode recognizes any of these tags, the proper indicator will show up in Report Navigator and of course at the top bar:
Pay attention to the colon at the end of each tag. Tags can be placed anywhere in the message.
]]>UICollectionView
. It’s way more customizable than his older brother UITableView
. Nowadays I use collection view even more often than table view. With iOS 9 it supports easy reordering. Before it wasn’t possible out of the box, and to do so means painful work. Let’s have look at the API. You can find the accompanying Xcode project on GitHub.
The easiest way to add easy reordering is to use UICollectionViewController
. It now has a new property called installsStandardGestureForInteractiveMovement
which adds standard gestures to reorder cells. This property is true
by default, which means that there’s only one method we should to override to get things working.
1 2 3 4 5 |
|
The collection view infers that items can be moved because moveItemAtIndexPath
is overrired.
Things go complicated when we want to use a simple UIViewController
with collection view. We also need to implement UICollectionViewDataSource
methods mentioned above, but we need to rewrite installsStandardGestureForInteractiveMovement
. No worries, it’s also easily supported.UILongPressGestureRecognizer
is a continuous gesture recognizer and fully supports panning.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
|
We stored selected index path obtained in long press gesture handler and depending on wether it has any value we allow to pan gesture to kick in. Then, we call some new collection view methods accordingly to the gesture state:
beginInteractiveMovementForItemAtIndexPath(indexPath: NSIndexPath)
which starts interactive movement for cell at specific index pathupdateInteractiveMovementTargetPosition(targetPosition: CGPoint)
which updates interactive movement target position during gestureendInteractiveMovement()
which ends interactive movement after you finish pan gesturecancelInteractiveMovement()
which cancels interactive movementAnd this makes handling pan gesture obvious.
The behavior is the same as with standard UICollectionViewController
. Really cool, but what makes it even cooler is that we can apply reordering to collection view with our custom collection view layout. Check interactive movement with simple waterfall layout.
Uhm, looks cool, but what if we don’t want to change cell size during movement? Selected cell size during interactive movement should remain the same. This is possible. UICollectionViewLayout
also gets additional methods to handle reordering.
1 2 3 4 5 6 7 8 |
|
The former is called during the cells interactive movement with target and previous cell’s indexPaths. The next one is similar, but it’s called just after interactive movement ends. With this knowledge we can achieve our requirement using one little trick.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Solution is straightforward. Grab previous and target index paths of currently moving cell. Then call UICollectionViewDataSource
method to move this items around.
Without a doubt, a collection view reordering is a fantastic addition. UIKit engineers made awesome job! :)
P.S: I would like to thanks Douglas Hill for hinting out some improvements in our code. Thanks Douglas, keep up the good work!
]]>iOS has some gotchas regarding multithread, things that if you don’t respect, may cause your application to crash or hang the users interface, for example:
We can solve those situations by using the so called Symbolic Breakpoints
and share those breakpoints with your team. Thereby, every developer can take advantage of that, and get notified, when they occur.
To help you out, we created a bunch of shared breakpoints and integrate them into your project is very easy:
- Go to your .xcodeproj
or .xcworkspace
file, right click on it, and choose Show Package Contents
.
- Open the folder xcshareddata
, then xcdebugger
(create them if not exists).
- Breakpoints are saved into Breakpoints_v2.xcbkptlist
.
- Now you just have to paste the following content into the <Breakpoints>
node.
(We could also add those by using LLDB
commands, but those won’t show up on the Breakpoints navigator)
Our list of useful breakpoints is available here
Now, whenever the breakpoint conditions are satisfied, you’ll be notified and will have a chance to quickly fix your code, before it crashes into the users hand!
]]>