iOS Impression Event Helper
A Mobile Analytics Event Story
The Backstory
Recently, one of my colleague who works for marketing department came around our team and said that he want to add just an another type of their exciting analytic events to our iOS app, named product listing impression. I have to confess that we love to implement marketing stuffs as whole team, who would not enjoy writing lots of junk code for just adding new analytic events in almost each sprint, instead of creating exciting new features for users.
So, first thing first, what does “impression” event mean ? Basically it means,
An event that occurs when a user sees a content.
Sending an event from app is an easy job (at least in most cases), but a small part of info from job’s description mentioned that there may be a challenge about this kind of event. When a user sees a content of cell completely, it count as impression and its okay to send it via event wrapper. But, if user sees less than half of a cell’s content, it should not counted as impression and no event should be sent in such case. In addition to this constraint, there is one more rule to be aware of. In terms of clarity, lets define our rules as follows,
- User should see more than half of a cell to count this event as impression
- Events which are already sent should not send again, ever if user sees these cells again.
Unfortunately there is no method or callback are provided from UICollectionView to use directly in such cases. Therefore, let’s write an impression event handler to detect which cells are seen by users, as enough as to count as impression. ✌️
Coding Part
First thing first, lets create our handler class, I named it ListingImpressionStalker (and yes, actually this naming defines what it really does), and define two variables with a basic initializer and a public method;
minimumPercentageOfCell is our ratio constraint related with the minimum percentage of seen part of the cell viewed by user to count as impression, collectionView is just a weak collectionView reference which is tracked for events.
Lets start to write some code for the stalkCells() method. First we need cells which are currently visible to user. Lucy for us, UICollectionView has a method named visibleCells() which returns visible cell instances currently visible. We should get these cells by calling this method, then percentage of viewed area calculation should be made for each cell by iterating them. So lets put these into code,
Steps followed in this method are really simple,
- Use guard statement to create local variables indexPath and layoutAttributes safely for cell.
- Find cell’s true position in the superview.
- Calculate intersection rect using collectionView’s frame and cell’s frame in superview which is calculated one line above.
- Calculate percentage of intersection and return it.
Thats it. Since we know percentage of the viewed area of the related cell, we can decide whether this view should be count as impression event or not, depends on the return value of this method. Lets create a protocol to send index paths we found using delegate pattern.
Using sendEventForCell(atIndexPath indexPath:Indexpath) method of this protocol, we can send index paths to class which is conforming ListingImpressionStalkerDelegate.
We have iterated visible cells and view percentage calculation has done for each cell. In terms of requirements, there is one last thing left, lets remember our second rule,
Already sent events should not send again ever if user sees these cells again.
To achieve this, we can easily create an array to store already sent index paths. Is it enough ? Maybe for the most time, yes it is; however we should make it as flexible as possible to cover many cases. To leave this choice to the user, lets create a protocol named ListingImpressionItem.
Cells which are belong to the collection view we tracked should conform this protocol to provide unique identifier. Now we can store these unique ids instead of index paths to prevent sending new event again. After defining ListingImpressionStalkerDelegate and ListingImpressionItem protocols, we can complete our stalkCells() method as follows,
Final Words
In the end of the story, we have completed our simple impression event handler. After conforming protocols mentioned above and implementing their methods, calling stalkCells() in viewDidAppear() and scrollViewDidScroll() methods would be enough. Thanks to the ListingImpressionStalkerDelegate, sendEventForCell() method is invoked automatically with index paths of cells which are seen more than half of their content, like following code snippet,
For those who do not want to make dirty their hands, completed code is in the following link,
Happy coding!