Where to call the reloadData when updating tableview? - ios

I am very new to swift programming so probably asking you a basic question but something I need to know.
I have an implementation where I am chatting with a bot so to speak. So the control flow is this:
I say "hi" this has to be reflected in the "chat" box and then the response that comes back from the web service also has to become a chat message.
Obviously, my messages and the other response from the web service should be of different colours and styles and I am doing that in my tableView function.
Here is my tableView code
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:tblCell = tblCell()
let font = UIFont(name:"Helvetica" , size: 14)
if(tableView.isEqual(messageTableView)) {
var chatMessage:ChatMessage = self.messageArray[indexPath.row]
cell=self.messageTableView.dequeueReusableCellWithIdentifier("MessageCell") as! tblCell
dispatch_async(dispatch_get_main_queue()) {
//Determining the size of the chat box
cell.messageText.sizeToFit()
cell.messageText.text = chatMessage.message
cell.messageText.numberOfLines = 0
cell.messageText.font = font
var frame: CGRect = cell.messageText.frame
cell.messageText.layer.cornerRadius = 10
cell.messageText.layer.masksToBounds = true
//if it is a user input message use this
if(chatMessage.messageType == "user") {
cell.messageText.textAlignment = NSTextAlignment.Right
cell.messageText.backgroundColor = self.UIColorFromRGB(0x0099FF)
cell.messageText.textColor = UIColor.whiteColor()
//code to right align the label
if(frame.width <= 148) {
frame.origin.x = 148 - frame.width
}
else {
frame.origin.x = 0
}
cell.messageText.frame = frame
} else if(chatMessage.messageType == “bot”) {
cell.messageText.textAlignment = NSTextAlignment.Left
cell.messageText.backgroundColor = UIColor.lightGrayColor()
}
var size:CGSize = CGSize(width: frame.width + 20, height: frame.height + 20)
cell.messageText.sizeThatFits(size)
if tableView.contentSize.height > tableView.frame.size.height && self.shouldScrollToLastRow {
let offset = CGPoint(x: 0, y: tableView.contentSize.height - tableView.frame.size.height)
tableView.setContentOffset(offset, animated: false)
self.shouldScrollToLastRow = false
}
}
return cell
}
return cell
}
Now I am experiencing trouble with the size of the message as it doesn't return the right size all the time. Meaning, as I scroll up and down, the size of the boxes keep changing.
I am thinking the problem is with reloadData() and I am not sure where I should be calling it.
Please note that I have an asynchronous request parse code written down and updating my chat from the response of the request.
What am I doing wrong?
Please help
Nikhil

Related

Cells with Dynamically created Heights overlap

Hi im newer to IOS dev and Im more familiar with web dev. I am running into an issue where my cells are originally rendered how I would expect them to, but after scrolling to the bottom and scrolling back to the top of my screen I noticed that the cells begin to overlap each other. After reading other stack overflow posts I am starting to think that it has to do with how I create the cells. I am attempting to create multiple labels in a cell with a for loop similar to how someone would with PHP for web dev and im wondering if this is the proper way to do it/ is this a possible cause.
for i in 0...bars.count-1 {
var barLabelView:UIView = UIView()
var barLabel:UILabel = UILabel()
barLabelView.frame = CGRect(x: 20, y: CGFloat(20 + (70 * i)), width: barView.frame.width-40, height: 50)
barLabelView.backgroundColor = UIColor(displayP3Red: 27/255.0, green: 99/255.0, blue: 222/255.0, alpha: 1)
barLabelView.layer.cornerRadius = 10
barLabel.frame = CGRect(x: 0, y: 0, width: barLabelView.frame.width-10, height: 50)
barLabel.text = bars[i]
barLabel.textAlignment = .center
barLabel.numberOfLines = 0
barLabel.font = UIFont(name: "Chalkboard SE", size: 15)
barView.addSubview(barLabelView)
barLabelView.addSubview(barLabel)
}
Also heres how i set the height of the cell:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let crawlNameText = self.posts[indexPath.row].text
let size = CGSize(width: view.frame.width - 40, height: 1000)
let options = NSStringDrawingOptions.usesFontLeading.union(.usesLineFragmentOrigin)
let estimatedCrawlNameFrame = NSString(string: crawlNameText).boundingRect(with: size, options: options, attributes: [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 16)], context: nil)
let bars = posts[indexPath.row].bars.components(separatedBy: ", ")
let buds = posts[indexPath.row].buds.components(separatedBy: ", ")
if (self.posts[indexPath.row].type == "crawl") {
var cellHeightP1 = CGFloat(estimatedCrawlNameFrame.height + 110 + 20 + 20 + 20 + 40 + 60)
var cellHeightP2:CGFloat = CGFloat( 80 * bars.count)
var cellHeightP3:CGFloat = CGFloat( 80 * buds.count)
var cellHeight = cellHeightP1 + cellHeightP2 + cellHeightP3
return cellHeight
} else {
return estimatedCrawlNameFrame.width + 110 + 20
}
}
and here is my cellForRowAt function
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = nfTV.dequeueReusableCell(withIdentifier: "cellId", for: indexPath) as! newsFeedCell
// Im guessing I would set the cell to nill here to clear the buttons I made
cell.setPost(post: posts[indexPath.row])
if (cell.profilePic != nil){
cell.profilePic.layer.cornerRadius = cell.profilePic.bounds.height / 2
cell.profilePic.clipsToBounds = true
}
cell.backgroundColor = UIColor.lightGray
print("made it here")
print(indexPath.row)
cell.frame = CGRect(x: 0, y: 0, width: cell.frame.width, height: cell.frame.height)
return cell
}
I read that I might have to clear my cell before reusing it but im not sure how to set a cell to nil. I am also wondering if using a collection view would work better but I dont know the difference between that and a tableview.
Any help or suggestions is appreciated, thanks.
I answered my own question but I guess Ill leave this up in case it helps anyone in the future
I added the following lines of code at my comment in the cellForRowAt function to remove the buttons
for v in cell.barView.subviews{
v.removeFromSuperview()
}
for v in cell.budsView.subviews{
v.removeFromSuperview()
}
The issue was caused by some cells having more buttons than others so cells with less buttons were rendered with more buttons than necessary making it appear like it was overlap but in reality it was just recycled buttons.

Why in UITableView, cellForRowAtIndexPath is called before heightForRowAtIndexPath

I have breakpoints in both the two methods. The cellForRowAtIndexPath is always called before heightForRowAtIndexPath.
The problem is I have a logic code in cellForRowAtIndexPath that depends on the row height.
Currently, the row height I get inside cellForRowAtIndexPath is always 0.
Is there a way to let heightForRowAtIndexPath to be called before cellForRowAtIndexPath?
If not, how to call heightForRowAtIndexPatch explicitly in my code?
EDIT:
Here is my code for cellForRowAtIndexPath:
let slideshowCell = tableView.dequeueReusableCell(withIdentifier: "SlideShowCell") as! SlideShowTableViewCell
slideshowCell.delegate = self
slideshowCell.news = featuredNews
return slideshowCell
and here is my code for heightForRowAtIndexPatch:
let filterApplied = categoryNews.count != filteredCategoryNews.count
if featuredNews.count == 0 || filterApplied
{
return 0
}
else
{
return 530
}
and when I set featuredNews to slideshowCell.news, I run this method in the slideshowCell.news's didSet property observer:
private func populateSlideshowScrollView()
{
let imagesCount = CGFloat(slideshowNews.count)
// set the scrollView's content size to the size of all the images
scrollView.contentSize = CGSize(width: scrollView.frame.width * imagesCount, height: scrollView.frame.height)
// Remove subviews of ScrollView before populating it with new images
for subview in scrollView.subviews
{
subview.removeFromSuperview()
}
// populate the scrollView with images form the 'slideshowNews' property
for i in 0..<slideshowNews.count
{
let imgView = UIImageView(frame: CGRect(x: scrollView.frame.width * CGFloat(i),
y: scrollView.bounds.origin.y,
width: scrollView.frame.width,
height: scrollView.frame.height))
imgView.contentMode = .scaleAspectFill
imgView.clipsToBounds = true
imgView.image = slideshowNews[i].image
scrollView.addSubview(imgView)
}
// set scrollview to the first page from the right, only the first two times this method called.
// After that the current page of page control should be in the correct position
if numberOfRefresh < 2
{
scrollView.setContentOffset(CGPoint(x: scrollView.frame.width * (imagesCount - 1), y: 0), animated: false)
newsTitleLabel.text = slideshowNews.last?.title
sourceLabel.text = slideshowNews.last?.source.name
numberOfRefresh += 1
}
scrollToPage(page: pageControl.currentPage, animated: false) // to update scrollView's contentOffset
}
The problem is that scrollView.frame.height will always return zero, because heightForRowAtIndexPath is not yet called at this point.

Resizing UICollectionView with Custom Layout after deleting cells

I downloaded this Pintrest-esc Custom Layout for my CollectionView from : https://www.raywenderlich.com/164608/uicollectionview-custom-layout-tutorial-pinterest-2 (modified it a little bit to do with cache code)
So the layout works fine, i got it set up so when you scroll to the bottom, i make another API call, create and populate additional cells.
Problem: If a User scrolls down and loads some more cells (lets say 20 for example) and then uses the "Search Feature" i have implemented at the top, it will then filter some of the data via price from MinRange - MaxRange leaving you with (lets say 5 results), thus deleting some cells and repopulating those. BUT - All that space and scrollable space that existed for the first 20 cells still exists as blank white space.... How can i remove this space ? and why can it resize when adding more cells, but not when removing them ?
Code of my API Call:
DispatchQueue.global(qos: .background).async {
WebserviceController.GetSearchPage(parameters: params) { (success, data) in
if success
{
if let products = data!["MESSAGE"] as? [[String : AnyObject]]
{
self.productList = products
}
}
DispatchQueue.main.async(execute: { () -> Void in
self.pintrestCollectionView.reloadData()
self.pintrestCollectionView.collectionViewLayout.invalidateLayout()
self.pintrestCollectionView.layoutSubviews()
})
}
}
Code Of Custom Layout Class & protocol:
protocol PinterestLayoutDelegate: class {
func collectionView(_ collectionView:UICollectionView, heightForPhotoAtIndexPath indexPath:IndexPath) -> CGFloat
}
class PintrestLayout: UICollectionViewFlowLayout {
// 1
weak var delegate : PinterestLayoutDelegate!
// 2
fileprivate var numberOfColumns = 2
fileprivate var cellPadding: CGFloat = 10
// 3
fileprivate var cache = [UICollectionViewLayoutAttributes]()
// 4
fileprivate var contentHeight: CGFloat = 0
fileprivate var contentWidth: CGFloat {
guard let collectionView = collectionView else {
return 0
}
let insets = collectionView.contentInset
return collectionView.bounds.width - (insets.left + insets.right)
}
// 5
override var collectionViewContentSize: CGSize {
return CGSize(width: contentWidth, height: contentHeight)
}
override func prepare() {
// 1
//You only calculate the layout attributes if cache is empty and the collection view exists.
/*guard cache.isEmpty == true, let collectionView = collectionView else {
return
}*/
cache.removeAll()
guard cache.isEmpty == true || cache.isEmpty == false, let collectionView = collectionView else {
return
}
// 2
//This declares and fills the xOffset array with the x-coordinate for every column based on the column widths. The yOffset array tracks the y-position for every column.
let columnWidth = contentWidth / CGFloat(numberOfColumns)
var xOffset = [CGFloat]()
for column in 0 ..< numberOfColumns {
xOffset.append(CGFloat(column) * columnWidth)
}
var column = 0
var yOffset = [CGFloat](repeating: 0, count: numberOfColumns)
// 3
//This loops through all the items in the first section, as this particular layout has only one section.
for item in 0 ..< collectionView.numberOfItems(inSection: 0) {
if collectionView.numberOfItems(inSection: 0) < 3
{
collectionView.isScrollEnabled = false
} else {
collectionView.isScrollEnabled = true
}
let indexPath = IndexPath(item: item, section: 0)
// 4
//This is where you perform the frame calculation. width is the previously calculated cellWidth, with the padding between cells removed.
let photoHeight = delegate.collectionView(collectionView, heightForPhotoAtIndexPath: indexPath)
let height = cellPadding * 2 + photoHeight
let frame = CGRect(x: xOffset[column], y: yOffset[column], width: columnWidth, height: height)
let insetFrame = frame.insetBy(dx: 7, dy: 4)
collectionView.contentInset = UIEdgeInsets.init(top: 15, left: 12, bottom: 0, right: 12)
// 5
//This creates an instance of UICollectionViewLayoutAttribute, sets its frame using insetFrame and appends the attributes to cache.
let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath)
attributes.frame = insetFrame
cache.append(attributes)
// 6
//This expands contentHeight to account for the frame of the newly calculated item.
contentHeight = max(contentHeight, frame.maxY)
yOffset[column] = yOffset[column] + height
column = column < (numberOfColumns - 1) ? (column + 1) : 0
}
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]?
{
var visibleLayoutAttributes = [UICollectionViewLayoutAttributes]()
// Loop through the cache and look for items in the rect
for attributes in cache {
if attributes.frame.intersects(rect) {
visibleLayoutAttributes.append(attributes)
}
}
return visibleLayoutAttributes
}
FYI: In MainStoryboard, i disabled "Adjust Scroll View Insets" as many of other threads and forums have suggested...
I'm guessing you've already found the answer, but I'm posting here for the next person since I ran into this issue.
The trick here is contentHeight actually never gets smaller.
contentHeight = max(contentHeight, frame.maxY)
This is a nondecreasing function.
To fix it, just set contentHeight to 0 if prepare is called:
guard cache.isEmpty == true || cache.isEmpty == false, let
collectionView = collectionView else {
return
}
contentHeight = 0

How to set UICollectionView bottom padding and scrolling size

Hello I have working uicollectionview custom layout and i have issuesfor bottom padding and scrolling sizes. Under below picture you can see;
Also top side first cell always stays on top when scrolling ( Left side cell must be always stay right now no problem there , but top side cell must be scroll when scrolling )
I try to set in viewDidLoad under below codes but dont work
self.automaticallyAdjustsScrollViewInsets = false
self.collectionView.contentInset = UIEdgeInsetsMake(20, 20, 120, 100);
My custom collectionview layout file
import UIKit
public var CELL_HEIGHT = CGFloat(22)
protocol CustomCollectionViewDelegateLayout: NSObjectProtocol {
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, widthForItemAtIndexPath indexPath: NSIndexPath) -> CGFloat
}
class CustomCollectionViewLayout: UICollectionViewLayout {
// Used for calculating each cells CGRect on screen.
// CGRect will define the Origin and Size of the cell.
let STATUS_BAR = UIApplication.sharedApplication().statusBarFrame.height
// Dictionary to hold the UICollectionViewLayoutAttributes for
// each cell. The layout attribtues will define the cell's size
// and position (x, y, and z index). I have found this process
// to be one of the heavier parts of the layout. I recommend
// holding onto this data after it has been calculated in either
// a dictionary or data store of some kind for a smooth performance.
var cellAttrsDictionary = Dictionary<NSIndexPath, UICollectionViewLayoutAttributes>()
// Defines the size of the area the user can move around in
// within the collection view.
var contentSize = CGSize.zero
// Used to determine if a data source update has occured.
// Note: The data source would be responsible for updating
// this value if an update was performed.
var dataSourceDidUpdate = true
weak var delegate: CustomCollectionViewDelegateLayout?
override func collectionViewContentSize() -> CGSize {
return self.contentSize
}
override func prepareLayout() {
// Only update header cells.
if !dataSourceDidUpdate {
// Determine current content offsets.
let xOffset = collectionView!.contentOffset.x
let yOffset = collectionView!.contentOffset.y
if collectionView?.numberOfSections() > 0 {
for section in 0...collectionView!.numberOfSections()-1 {
// Confirm the section has items.
if collectionView?.numberOfItemsInSection(section) > 0 {
// Update all items in the first row.
if section == 0 {
for item in 0...collectionView!.numberOfItemsInSection(section)-1 {
// Build indexPath to get attributes from dictionary.
let indexPath = NSIndexPath(forItem: item, inSection: section)
// Update y-position to follow user.
if let attrs = cellAttrsDictionary[indexPath] {
var frame = attrs.frame
// Also update x-position for corner cell.
if item == 0 {
frame.origin.x = xOffset
}
frame.origin.y = yOffset
attrs.frame = frame
}
}
// For all other sections, we only need to update
// the x-position for the fist item.
} else {
// Build indexPath to get attributes from dictionary.
let indexPath = NSIndexPath(forItem: 0, inSection: section)
// Update y-position to follow user.
if let attrs = cellAttrsDictionary[indexPath] {
var frame = attrs.frame
frame.origin.x = xOffset
attrs.frame = frame
}
}
}
}
}
// Do not run attribute generation code
// unless data source has been updated.
return
}
// Acknowledge data source change, and disable for next time.
dataSourceDidUpdate = false
var maxWidthInASection = CGFloat(0)
// Cycle through each section of the data source.
if collectionView?.numberOfSections() > 0 {
for section in 0...collectionView!.numberOfSections()-1 {
// Cycle through each item in the section.
if collectionView?.numberOfItemsInSection(section) > 0 {
var prevCellAttributes: UICollectionViewLayoutAttributes?
for item in 0...collectionView!.numberOfItemsInSection(section)-1 {
let cellIndex = NSIndexPath(forItem: item, inSection: section)
guard let width = delegate?.collectionView(collectionView!, layout: self, widthForItemAtIndexPath: cellIndex) else {
print("Please comform to CustomCollectionViewDelegateLayout protocol")
return
}
// Build the UICollectionVieLayoutAttributes for the cell.
var xPos = CGFloat(0)
let yPos = CGFloat(section) * CELL_HEIGHT
if let prevCellAttributes = prevCellAttributes {
xPos = CGRectGetMaxX(prevCellAttributes.frame)
}
let cellAttributes = UICollectionViewLayoutAttributes(forCellWithIndexPath: cellIndex)
cellAttributes.frame = CGRect(x: xPos, y: yPos, width: width, height: CELL_HEIGHT)
// Determine zIndex based on cell type.
if section == 0 && item == 0 {
cellAttributes.zIndex = 4
} else if section == 0 {
cellAttributes.zIndex = 3
} else if item == 0 {
cellAttributes.zIndex = 2
} else {
cellAttributes.zIndex = 1
}
// Save the attributes.
cellAttrsDictionary[cellIndex] = cellAttributes
prevCellAttributes = cellAttributes
let maxX = CGRectGetMaxX(cellAttributes.frame)
if maxWidthInASection < maxX {
maxWidthInASection = maxX
}
}
}
}
}
// Update content size.
let contentWidth = maxWidthInASection
let contentHeight = Double(collectionView!.numberOfSections())
self.contentSize = CGSize(width: Double(contentWidth), height: contentHeight)
self.contentSize.height = CGFloat(Double(collectionView!.numberOfSections()))
}
override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
// Create an array to hold all elements found in our current view.
var attributesInRect = [UICollectionViewLayoutAttributes]()
// Check each element to see if it should be returned.
for cellAttributes in cellAttrsDictionary.values.elements {
if CGRectIntersectsRect(rect, cellAttributes.frame) {
attributesInRect.append(cellAttributes)
}
}
// Return list of elements.
return attributesInRect
}
override func layoutAttributesForItemAtIndexPath(indexPath: NSIndexPath) -> UICollectionViewLayoutAttributes? {
return cellAttrsDictionary[indexPath]!
}
override func shouldInvalidateLayoutForBoundsChange(newBounds: CGRect) -> Bool {
return true
}
}
I try change collecionview properties in storyboard but doesnt works also i attached current collectionview object properties picture under below
Also i selected zoom 4 but zoom feature doesnt work ? why ? it must be work also zoom feature.
I know this is too late to answer, but this could be useful to other users.
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
collectionView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 50, right: 0)
}
This what worked for me:
messagesCollectionView.contentInset.top = 100
messagesCollectionView.contentInset.bottom = 80
This can be also done on IB under section insets...

Oblique table view cells in iOS

How can I implement this? A table view with oblique cells. I was thinking first to make the cells overlap and cut out a piece, but I can't make it work.
Now the single solution I can think of is to download the second image in first cell and cut out the top triangle and add to the first cell. But that wouldn't be too optimal memory wise and processing wise if the user is scrolling through the list.
I appreciate any advice, thank you!
I've done something similar like this but I didn't use UITableView or UICollectionView.
What I use is having one UIImageView(AView) on top of the other UIImageView(BView) in view hieararchy. So I add UISwipeGestureRecognizer to BView .And at the top of BView I've added a seperator view(when VC load user could not see it). And I basically animating BView however I want.
But since they are not cells in UITableView you can't give "pulling" behavior to user which is a UX disadvantage for your app.
I solved it the following way. I used UICollectionView in the end because I couldn't find a way to overlap nicely the cells from UITableView. So first I made a custom layout which looks like this:
CustomCollectionViewFlowLayout.swift
import UIKit
class CustomCollectionViewFlowLayout: UICollectionViewFlowLayout {
override func collectionViewContentSize() -> CGSize {
let xSize = self.itemSize.width
let ySize = CGFloat(self.collectionView!.numberOfItemsInSection(0)) * self.itemSize.height
var size = CGSizeMake(xSize, ySize)
if self.collectionView!.bounds.size.width > size.width {
size.width = self.collectionView!.bounds.size.width
}
if self.collectionView!.bounds.size.height > size.height {
size.height = self.collectionView!.bounds.size.height
}
return size
}
override func layoutAttributesForElementsInRect(rect: CGRect) -> [AnyObject]? {
let attributesArray = super.layoutAttributesForElementsInRect(rect) as! [UICollectionViewLayoutAttributes]
let numberOfItems = self.collectionView?.numberOfItemsInSection(0)
for attribute in attributesArray {
let xPosition = attribute.center.x
var yPosition = attribute.center.y
if attribute.indexPath.row == 0 {
attribute.zIndex = Int(INT_MAX)
} else {
yPosition -= CGFloat(60 * attribute.indexPath.row)
attribute.zIndex = numberOfItems! - attribute.indexPath.row
}
attribute.center = CGPointMake(xPosition, yPosition)
}
return attributesArray
}
override func layoutAttributesForItemAtIndexPath(indexPath: NSIndexPath) -> UICollectionViewLayoutAttributes! {
return UICollectionViewLayoutAttributes(forCellWithIndexPath: indexPath)
}
}
Then I used paths and shapes to cut out that part and also draw a white rectangle. So it looks like this:
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("ChallengeCollectionViewCell", forIndexPath: indexPath) as! ChallengeCollectionViewCell
cell.challengeImage.sd_setImageWithURL(NSURL(string: STATIC_IMAGE_URL), completed: nil)
let trianglePath = CGPathCreateMutable()
CGPathMoveToPoint(trianglePath, nil, 0, 0)
CGPathAddLineToPoint(trianglePath, nil, 0, cell.challengeImage!.frame.size.height)
CGPathAddLineToPoint(trianglePath, nil, cell.challengeImage!.frame.size.width, cell.challengeImage!.frame.size.height - 50)
CGPathAddLineToPoint(trianglePath, nil, cell.challengeImage!.frame.width, 0)
CGPathAddLineToPoint(trianglePath, nil, 0, 0)
CGPathCloseSubpath(trianglePath)
let shapeLayer = CAShapeLayer()
shapeLayer.frame = cell.challengeImage!.frame
shapeLayer.path = trianglePath
cell.challengeImage.layer.mask = shapeLayer
cell.challengeImage.layer.masksToBounds = true
let linePath = CGPathCreateMutable()
CGPathMoveToPoint(linePath, nil, 0, cell.challengeImage!.frame.size.height)
CGPathAddLineToPoint(linePath, nil, cell.challengeImage!.frame.size.width, cell.challengeImage!.frame.size.height - 50)
CGPathCloseSubpath(linePath)
let lineShape = CAShapeLayer()
lineShape.path = linePath
lineShape.lineWidth = 10
lineShape.strokeColor = UIColor.whiteColor().CGColor
cell.challengeImage.layer.addSublayer(lineShape)
return cell
}
I hope it will be useful for someone who runs into the same problem. Thanks and best wishes!

Resources