Instruments show "_NSContiguousstring" memory leak when scrolling UITableView - ios

I have a UItableView which consist of 10 element. I opened Instruments to catch the memory leaks and when I scroll tableView, It started to give memory leaks. In Instruments I tried to find which causes the leaks but can't figure out, It says "_NScontiguousstring" for whole leaks.
I found some solutions for Objective-C which they check If cell is nil in "CellForRowAt" function. I don't think it is useful for Swift but I tried and as expected It doesn't work.
Memory Leak UITableView
My question is what can cause this kind of memory leak?
Devices I test it;
iPhone X on 11.3.1
iPhone 6 11.2.5
Controller Class;
class TableViewController: UITableViewController {
let teamModel = TeamModel(uid: "adsada", name: "First Team ", idea: "idea 1", slogan: "Slogan 1", university: "dasda", image: "info", isActive: true)
let teamModel2 = TeamModel(uid: "adsada", name: "Team 2", idea: "idea 2", slogan: "adasd", university: "dasda", image: "info", isActive: true)
let teamModel3 = TeamModel(uid: "adsada", name: "Team 3", idea: "idea 3", slogan: "adasd", university: "dasda", image: "info", isActive: true)
let teamModel4 = TeamModel(uid: "adsada", name: "Team 4", idea: "idea 4", slogan: "adasd", university: "dasda", image: "info", isActive: true)
let teamModel5 = TeamModel(uid: "adsada", name: "Team 5", idea: "idea 5", slogan: "adasd", university: "dasda", image: "info", isActive: true)
let teamModel6 = TeamModel(uid: "adsada", name: "Team 6", idea: "idea 6", slogan: "adasd", university: "dasda", image: "info", isActive: true)
let teamModel7 = TeamModel(uid: "adsada", name: "Team 7", idea: "idea 7", slogan: "adasd", university: "dasda", image: "info", isActive: true)
var data: [TeamModel] = []
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(mainTableCell.self, forCellReuseIdentifier: "mainTableCell")
data = [teamModel,teamModel2,teamModel3,teamModel4,teamModel5,teamModel6,teamModel7]
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return data.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "mainTableCell", for: indexPath) as! mainTableCell
let cell_data = data[indexPath.row]
cell.cell_data = cell_data
return cell
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 120
}
}
Cell Class;
class mainTableCell: UITableViewCell{
var cell_data: TeamModel?{
didSet{
guard let unwrappedCell = cell_data else { return }
if let url = unwrappedCell.imageURL{
profileImage.image = UIImage(named: "info")
} else{
self.profileImage.image = UIImage(named: "info")
}
self.teamLbl.text = unwrappedCell.name
mainBackground.backgroundColor = UIColor.gray
}
}
let mainBackground: UIView = {
let v = UIView()
v.layer.cornerRadius = 8
v.layer.masksToBounds = true
return v
}()
var isVoteable: Bool = false
//let shadowView = ShadowView()
let profileImage: UIImageView = {
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds = true
imageView.layer.masksToBounds = true
return imageView
}()
let teamLbl: UILabel = {
let label = UILabel()
label.textColor = UIColor.black
label.numberOfLines = 1
label.adjustsFontSizeToFitWidth = true
return label
}()
let myVoteLbl: UILabel = {
let l = UILabel()
l.text = "Oyum: --"
return l
}()
let voteBtn: UIButton = {
let b = UIButton(type: .custom)
b.setImage(UIImage(named: "info"), for: .normal)
return b
}()
override init(style: UITableViewCellStyle, reuseIdentifier: String?){
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupViews()
}
func setupViews() {
self.backgroundColor = UIColor.white
self.mainBackground.addSubview(profileImage)
self.mainBackground.addSubview(teamLbl)
self.mainBackground.addSubview(voteBtn)
self.mainBackground.addSubview(myVoteLbl)
//self.addSubview(shadowView)
self.addSubview(mainBackground)
self.backgroundColor = UIColor.clear
profileImage.translatesAutoresizingMaskIntoConstraints = false
teamLbl.translatesAutoresizingMaskIntoConstraints = false
voteBtn.translatesAutoresizingMaskIntoConstraints = false
myVoteLbl.translatesAutoresizingMaskIntoConstraints = false
mainBackground.translatesAutoresizingMaskIntoConstraints = false
//shadowView.translatesAutoresizingMaskIntoConstraints = false
}
override func layoutSubviews() {
super.layoutSubviews()
// self.setCircularImageView()
mainBackground.anchor(self.topAnchor, left: self.leftAnchor, bottom: self.bottomAnchor, right: self.rightAnchor, topConstant: 10, leftConstant: 10, bottomConstant: 10, rightConstant: 10, widthConstant: 0, heightConstant: 0)
// shadowView.anchor(self.topAnchor, left: self.leftAnchor, bottom: self.bottomAnchor, right: self.rightAnchor, topConstant: 5, leftConstant: 5, bottomConstant: 5, rightConstant: 5, widthConstant: 0, heightConstant: 0)
profileImage.anchor(nil, left: self.mainBackground.leftAnchor, bottom: nil, right: nil, topConstant: 0, leftConstant: 10, bottomConstant: 0, rightConstant: 0, widthConstant: 60, heightConstant: 60)
profileImage.anchorCenterYToSuperview()
teamLbl.anchor(self.mainBackground.topAnchor, left: profileImage.rightAnchor, bottom: nil, right: self.voteBtn.leftAnchor, topConstant: 20, leftConstant: 20, bottomConstant: 0, rightConstant: 0, widthConstant: 0, heightConstant: 40)
myVoteLbl.anchor(nil, left: profileImage.rightAnchor, bottom: self.mainBackground.bottomAnchor, right: nil, topConstant: 0, leftConstant: 20, bottomConstant: 20, rightConstant: 0, widthConstant: 0, heightConstant: 0)
voteBtn.anchor(nil, left: nil, bottom: nil, right: self.mainBackground.rightAnchor, topConstant: 0, leftConstant: 0, bottomConstant: 0, rightConstant: 0, widthConstant: 80, heightConstant: 80)
voteBtn.anchorCenterYToSuperview()
}
func setCircularImageView() {
self.profileImage.layer.cornerRadius = CGFloat(roundf(Float(self.profileImage.frame.size.width / 2.0)))
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
EDIT: I add prepareForReuse method regarding to below answer but now cells show just white. Am I doing something wrong?
override func prepareForReuse() {
super.prepareForReuse()
teamLbl.text = ""
myVoteLbl.text = ""
profileImage.image = nil
}
I also make cell_data variable "weak var cell_data: TeamModel? and nil it in prepareForReuse() method but still same leaks are coming.
EDIT 2: Full project;
https://github.com/emreond/TableView-Memory-Leak-Project
EDIT 3: I found that when I add If check and change attributes inside didst of cell_data, some cells views look ruined. For example when I change teamLbl text color inside cell_data. In some cells, It looks ruined.
EDIT 4: When I comment anchor codes to check with reference of #Darp's answer,(I don't have anything seen on screen and don't have any constraint) It still continue to give leak.
EDIT 5: I'm still working on this leak but can't find any solution. Actually when I look what is in memory when tableView is on screen, I see that only 8 cell is on memory which looks like correct.

I have the same problem with _NSContiguousString. Even in an empty application with just one label, it shows a leak of 48 bytes.
I am not sure, but I have a guess that the reason for leaking might be bridging with NSString (I see also [_SwiftNativeNSStringBase retain] on the top of the stack trace).
I've found out that NSString itself might be considered as a leaking object by the Instruments because it has been implemented as a Singleton.
My own question is here: Memory leaks when assigning text to UILabel (iOS, Swift 4, XCode9)

First things first.
Inside layoutSubviews you are setting anchores. Why ? It's going to be called each time your cells will be called.
Instead of this, move
// self.setCircularImageView()
mainBackground.anchor(self.topAnchor, left: self.leftAnchor, bottom: self.bottomAnchor, right: self.rightAnchor, topConstant: 10, leftConstant: 10, bottomConstant: 10, rightConstant: 10, widthConstant: 0, heightConstant: 0)
// shadowView.anchor(self.topAnchor, left: self.leftAnchor, bottom: self.bottomAnchor, right: self.rightAnchor, topConstant: 5, leftConstant: 5, bottomConstant: 5, rightConstant: 5, widthConstant: 0, heightConstant: 0)
profileImage.anchor(nil, left: self.mainBackground.leftAnchor, bottom: nil, right: nil, topConstant: 0, leftConstant: 10, bottomConstant: 0, rightConstant: 0, widthConstant: 60, heightConstant: 60)
profileImage.anchorCenterYToSuperview()
teamLbl.anchor(self.mainBackground.topAnchor, left: profileImage.rightAnchor, bottom: nil, right: self.voteBtn.leftAnchor, topConstant: 20, leftConstant: 20, bottomConstant: 0, rightConstant: 0, widthConstant: 0, heightConstant: 40)
myVoteLbl.anchor(nil, left: profileImage.rightAnchor, bottom: self.mainBackground.bottomAnchor, right: nil, topConstant: 0, leftConstant: 20, bottomConstant: 20, rightConstant: 0, widthConstant: 0, heightConstant: 0)
voteBtn.anchor(nil, left: nil, bottom: nil, right: self.mainBackground.rightAnchor, topConstant: 0, leftConstant: 0, bottomConstant: 0, rightConstant: 0, widthConstant: 80, heightConstant: 80)
voteBtn.anchorCenterYToSuperview()
Just bellow setupViews() call.
Next thing is that you didn't implement prepareForReuse(), you need to nil the values which u are setting in cellForRow, willDislayCell` etc.
EDIT
var cell_data: TeamModel? - Marking it as optional doesn't make it weak reference, mark it as weak var and nil it every time cell gets reused.

Related

Tableviews delegate eats button click

I got a large UITableViewCell representing a place. Elements of the cell are two Buttons starButton and infoButton. Both of them have a targetAction which never gets executed and I'm clueless why.. All touches are being eaten by the didSelectRowAt by the tableview. The thing that gets me so confused is the fact that It all worked well some hours ago and I did not change properties of the two buttons. Does someone has an idea what's going on?
The Hierarchy looks like this:
UITableView
OverviewTableCell UITableViewCell
dotsButton, thumbnailImageView UIButton , UIImageView
blackView UIView
titleLabel, descriptionLabel, starButton, infoButton UILabel , UIButton
Cell:
class OverviewTableViewCell: UITableViewCell, ReusableView {
lazy var dotsButton: UIButton = {
let button = UIButton()
button.setImage(UIImage(named: GSSettings.UI.otherIcons.dotsHorizontal)?.withRenderingMode(.alwaysTemplate), for: .normal)
button.setImage(UIImage(named: GSSettings.UI.otherIcons.dotsVertical)?.withRenderingMode(.alwaysTemplate), for: .selected)
button.addTarget(self, action: #selector(seeMore), for: .touchUpInside)
button.fixHeightAndWidth(width: 28, height: 28)
button.tintColor = UIColor.gray
return button
}()
let thumbnailImageView: UIImageView = {
let imageview = UIImageView()
imageview.contentMode = .scaleAspectFill
imageview.clipsToBounds = true
imageview.image = UIImage(named: "testbild")
return imageview
}()
let blackView: UIImageView = {
let imageview = UIImageView()
imageview.backgroundColor = UIColor.black.withAlphaComponent(0.35)
return imageview
}()
let titleLabel : UILabel = {
let label = UILabel()
label.text = "Titel Titel"
label.font = GSSettings.UI.Fonts.helveticaMedium?.withSize(22)
label.textColor = UIColor.white
return label
}()
lazy var starButton: GSFavSpotButton = {
let button = GSFavSpotButton()
button.tintColor = UIColor.white//GSSettings.UI.Colors.nightOrange
button.addTarget(self, action: #selector(handleStarButton), for: .touchUpInside)
return button
}()
lazy var infoButton: GSInfoButton = {
let button = GSInfoButton()
button.tintColor = UIColor.white//GSSettings.UI.Colors.nightOrange
button.addTarget(self, action: #selector(handleInfoButton), for: .touchUpInside)
return button
}()
let addFriendView = GSInviteAFriendView()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
self.clipsToBounds = false
self.selectionStyle = .none
setupSubviews()
setupConstraints()
perform(#selector(printBounds), with: nil, afterDelay: 5)
}
func setupSubviews() {
self.addSubview(dotsButton)
self.addSubview(thumbnailImageView)
thumbnailImageView.addSubview(blackView)
blackView.addSubview(titleLabel)
blackView.addSubview(descriptionLabel)
blackView.addSubview(starButton)
blackView.addSubview(infoButton)
self.addSubview(addFriendView)
blackView.isHidden = true
descriptionLabel.isHidden = true
}
func setupConstraints() {
dotsButton.anchor(top: topAnchor, leading: nil, bottom: nil, trailing: trailingAnchor, paddingTop: 0, paddingLeading: 0, paddingBottom: 0, paddingTrailing: 16, width: 0, height: 0)
thumbnailImageView.anchor(top: dotsButton.bottomAnchor, leading: leadingAnchor, bottom: nil, trailing: trailingAnchor, paddingTop: 4, paddingLeading: 16, paddingBottom: 0, paddingTrailing: 16, width: 0, height: 0)
thumbnailImageView.heightAnchor.constraint(equalTo: thumbnailImageView.widthAnchor, multiplier: 9/16).isActive = true
blackView.fillSuperview(unsafeArea: true)
titleLabel.anchor(top: thumbnailImageView.topAnchor, leading: thumbnailImageView.leadingAnchor, bottom: nil, trailing: starButton.leadingAnchor, paddingTop: 8, paddingLeading: 8, paddingBottom: 0, paddingTrailing: 8, width: 0, height: 20)
infoButton.anchor(top: thumbnailImageView.topAnchor, leading: nil, bottom: nil, trailing: thumbnailImageView.trailingAnchor, paddingTop: 8, paddingLeading: 0, paddingBottom: 0, paddingTrailing: 8, width: 30, height: 30)
starButton.anchor(top: thumbnailImageView.topAnchor, leading: nil, bottom: nil, trailing: infoButton.leadingAnchor, paddingTop: 8, paddingLeading: 0, paddingBottom: 0, paddingTrailing: 4, width: 30, height: 30)
addFriendView.anchor(top: thumbnailImageView.bottomAnchor, leading: nil, bottom: nil, trailing: nil, paddingTop: -GSSettings.UI.Sizes.addFriendButtonSize/2 + 10, paddingLeading: 0, paddingBottom: 0, paddingTrailing: 0, width: GSSettings.UI.Sizes.addFriendButtonSize, height: GSSettings.UI.Sizes.addFriendButtonSize)
addFriendView.centerXAnchor.constraint(equalTo: centerXAnchor, constant: 0).isActive = true
}
#objc func seeMore() {
dotsButton.isSelected.toggle()
if dotsButton.isSelected {
blackView.isHidden = false
} else {
blackView.isHidden = false
}
layoutIfNeeded()
}
#objc func handleStarButton() {
starButton.isSelected.toggle()
}
#objc func handleInfoButton() {
infoButton.isSelected.toggle()
}
#objc func printBounds() {
print("::::")
print(thumbnailImageView.bounds)
print(infoButton.bounds)
print(starButton.bounds)
print("_____")
print(thumbnailImageView.frame)
print(infoButton.frame)
print(starButton.frame)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
extension UIView {
func anchor(top: NSLayoutYAxisAnchor?, leading: NSLayoutXAxisAnchor?, bottom: NSLayoutYAxisAnchor?, trailing: NSLayoutXAxisAnchor?, paddingTop: CGFloat, paddingLeading: CGFloat, paddingBottom: CGFloat, paddingTrailing: CGFloat, width: CGFloat, height: CGFloat) {
translatesAutoresizingMaskIntoConstraints = false
if let top = top {
topAnchor.constraint(equalTo: top, constant: paddingTop).isActive = true
}
if let leading = leading {
leadingAnchor.constraint(equalTo: leading, constant: paddingLeading).isActive = true
}
if let bottom = bottom {
bottomAnchor.constraint(equalTo: bottom, constant: -paddingBottom).isActive = true
}
if let trailing = trailing {
trailingAnchor.constraint(equalTo: trailing, constant: -paddingTrailing).isActive = true
}
if width != 0 {
widthAnchor.constraint(equalToConstant: width).isActive = true
}
if height != 0 {
heightAnchor.constraint(equalToConstant: height).isActive = true
}
}
Tableview:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: OverviewTableViewCell.reuseIdentifier, for: indexPath) as! OverviewTableViewCell
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: false)
delegate?.pushTo()
}
The printBounds() function in the cell shows that the frame and bounds are okay (I guess)
(0.0, 0.0, 382.0, 215.0)
(0.0, 0.0, 30.0, 30.0)
(0.0, 0.0, 30.0, 30.0)
(16.0, 32.0, 382.0, 215.0)
(344.0, 8.0, 30.0, 30.0)
(310.0, 8.0, 30.0, 30.0)
You can try
blackView.isUserInteractionEnabled = true
also add the subviews to
self.contentView and create the constraints of cell subviews with it

CollectionView cells not appearing correctly using mmPlayerView

I have a collectionview that contains a video, a caption, profile image and a few other labels in each cell. When I load the collection view the first cell loads perfectly. Everything is all showing in the correct position. The rest however is loaded incorrectly for example sometimes the video does not fit properly within the imageview so it looks like its been cut out or sometimes the caption doesn't show at all.
But when I scroll down more a cell might randomly show everything in the correct positions again. I am using a library MMPlayerView to load my videos into the cell. I have been trying to figure out why the first cell loads perfectly but then the rest doesn't?
I am trying to create a collectionview that just plays videos like Instagram. I've also build out the collectionview programmatically if someone needs to know.
viewController
lazy var mmPlayerLayer: MMPlayerLayer = {
let l = MMPlayerLayer()
l.cacheType = .memory(count: 5)
l.coverFitType = .fitToPlayerView
l.videoGravity = AVLayerVideoGravityResizeAspectFill
l.replace(cover: CoverA.instantiateFromNib())
return l
}()
#IBOutlet weak var newsfeedCollectionView: UICollectionView!
var videoPosts = [videoPost]()
override func viewDidLoad() {
super.viewDidLoad()
newsfeedCollectionView?.register(videoListCollectionViewCell.self, forCellWithReuseIdentifier: cellId)
newsfeedCollectionView.addObserver(self, forKeyPath: "contentOffset", options: [.new], context: nil)
newsfeedCollectionView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 20, right:0)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
self.updateByContentOffset()
self.startLoading()
}
fetchAllPosts()
}
fileprivate func landscapeAction() {
// just landscape when last result was finish
if self.newsfeedCollectionView.isDragging || self.newsfeedCollectionView.isTracking || self.presentedViewController != nil {
return
}
if UIDevice.current.orientation.isLandscape {
let full = UIStoryboard.init(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "FullScreenViewController") as! FullScreenViewController
MMLandscapeWindow.shared.makeKey(root: full, playLayer: self.mmPlayerLayer, completed: {
print("landscape completed")
})
}
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if keyPath == "contentOffset" {
self.updateByContentOffset()
NSObject.cancelPreviousPerformRequests(withTarget: self)
self.perform(#selector(startLoading), with: nil, afterDelay: 0.3)
} else {
super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
}
}
func fetchAllPosts() {
//posts are loaded from firebase
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return videoPosts.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! videoListCollectionViewCell
let postModelInfo = videoPosts[indexPath.item]
cell.post = postModelInfo
return cell
}
fileprivate func updateByContentOffset() {
let p = CGPoint(x: newsfeedCollectionView.frame.width/2, y: newsfeedCollectionView.contentOffset.y + newsfeedCollectionView.frame.width/2)
if let path = newsfeedCollectionView.indexPathForItem(at: p),
self.presentedViewController == nil {
self.updateCell(at: path)
}
}
fileprivate func updateCell(at indexPath: IndexPath) {
if let cell = newsfeedCollectionView.cellForItem(at: indexPath) as? videoListCollectionViewCell {
cell.delegate = self
cell.videoDelegate = self
// this thumb use when transition start and your video dosent start
mmPlayerLayer.thumbImageView.image = cell.photoImageView.image
// set video where to play
if !MMLandscapeWindow.shared.isKeyWindow {
mmPlayerLayer.playView = cell.photoImageView
}
// set url prepare to load
mmPlayerLayer.set(url: URL(string:(cell.post?.videoUrl)!), state: { (status) in
switch status {
case .failed(let err):
let alert = UIAlertController(title: "error", message: err.description, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
self.present(alert, animated: true, completion: nil)
case .ready:
print("Ready to Play")
case .playing:
print("Playing")
case .pause:
print("Pause")
case .end:
print("End")
default: break
}
})
cell.layoutIfNeeded()
}
}
#objc fileprivate func startLoading() {
if self.presentedViewController != nil {
return
}
// start loading video
mmPlayerLayer.startLoading()
self.landscapeAction()
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let post = videoPosts[indexPath.item]
let width = (view.frame.width)
let imageWidth = post.imageWidth?.floatValue,
imageHeight = post.imageHeight?.floatValue
let oldHeight = CGFloat(imageWidth! / imageHeight!)
let height = CGFloat(width / oldHeight + 138)
let rect = NSString(string: post.postCaption!).boundingRect(with: CGSize(width:view.frame.width, height:1000), options: NSStringDrawingOptions.usesFontLeading.union(NSStringDrawingOptions.usesLineFragmentOrigin), attributes: [NSFontAttributeName : UIFont.systemFont(ofSize: 14)], context: nil)
return CGSize(width:view.frame.width, height:rect.height + height)
}
CollectionViewCell
protocol mmPlayerDelegate{
func startLoading(for cell: videoListCollectionViewCell)
}
class videoListCollectionViewCell: UICollectionViewCell {
var delegate: PostCellDelegate?
var videoDelegate: videoDelegate?
var mmPlayerDelegate: mmPlayerDelegate?
var post: videoPost? {
didSet {
guard let postImageUrl = post?.imageUrl else { return }
self.photoImageView.sd_setImage(with: URL(string: postImageUrl), placeholderImage: UIImage(named: "blurLogo"))
self.userProfileImageView.sd_setImage(with: URL(string: post?.profilePic), placeholderImage: UIImage(named: "blurLogo"))
usernameLabel.text = post?.fullName
captionLabel.text = post!.postCaption
}
override func prepareForReuse() {
super.prepareForReuse()
post = nil
}
let userProfileImageView: CustomImageView = {
var iv = CustomImageView()
iv.image = UIImage(named:"blurLogo")
iv.contentMode = .scaleAspectFill
iv.translatesAutoresizingMaskIntoConstraints = false
iv.backgroundColor = UIColor.darkGray
iv.clipsToBounds = true
return iv
}()
var photoImageView: CustomImageView = {
var iv = CustomImageView()
iv.image = UIImage(named:"blurLogo")
iv.contentMode = .scaleAspectFill
iv.backgroundColor = UIColor.clear
iv.translatesAutoresizingMaskIntoConstraints = false
iv.clipsToBounds = true
iv.layer.masksToBounds = true
return iv
}()
let usernameLabel: UILabel = {
let label = UILabel()
label.text = ""
label.textColor = UIColor.white
label.font = UIFont.boldSystemFont(ofSize: 14)
return label
}()
let postDate: UILabel = {
let label = UILabel()
label.text = ""
label.font = UIFont.boldSystemFont(ofSize: 10)
label.textColor = UIColor.gray
return label
}()
let likeCount: UILabel = {
let label = UILabel()
label.text = "0"
label.textColor = UIColor.white
label.font = UIFont.systemFont(ofSize: 14)
return label
}()
let optionsButton: UIButton = {
let button = UIButton(type: .system)
button.translatesAutoresizingMaskIntoConstraints = false
button.setTitle("•••", for: .normal)
button.setTitleColor(.white, for: .normal)
return button
}()
lazy var likeButton: UIButton = {
let button = UIButton(type: .system)
let stencil = imageLiteral(resourceName: "like_unselected").withRenderingMode(.alwaysTemplate)
button.setImage(stencil, for: .normal)
button.tintColor = UIColor.white
button.addTarget(self, action: #selector(handleLike), for: .touchUpInside)
return button
}()
lazy var commentButton: UIButton = {
let button = UIButton(type: .system)
let stencil = imageLiteral(resourceName: "comment").withRenderingMode(.alwaysTemplate)
button.setImage(stencil, for: .normal)
button.tintColor = UIColor.white
button.addTarget(self, action: #selector(handleComment), for: .touchUpInside)
return button
}()
let captionLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.numberOfLines = 0
label.textColor = UIColor.white
label.font = UIFont.systemFont(ofSize: 14)
return label
}()
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(userProfileImageView)
addSubview(usernameLabel)
addSubview(optionsButton)
addSubview(photoImageView)
userProfileImageView.anchor(top: topAnchor, left: leftAnchor, bottom: nil, right: nil, paddingTop: 8, paddingLeft: 8, paddingBottom: 0, paddingRight: 0, width: 40, height: 40)
userProfileImageView.layer.cornerRadius = 40 / 2
usernameLabel.anchor(top: topAnchor, left: userProfileImageView.rightAnchor, bottom: photoImageView.topAnchor, right: optionsButton.leftAnchor, paddingTop: 0, paddingLeft: 8, paddingBottom: 0, paddingRight: 0, width: 0, height: 0)
photoImageView.anchor(top: userProfileImageView.bottomAnchor, left: leftAnchor, bottom: nil, right: rightAnchor, paddingTop: 16, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: 0, height: 0)
addSubview(postDate)
postDate.anchor(top: topAnchor, left: nil, bottom: photoImageView.topAnchor, right: rightAnchor, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 8, width: 0, height: 0)
optionsButton.anchor(top: photoImageView.bottomAnchor, left: nil, bottom: nil, right: rightAnchor, paddingTop: 15, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: 44, height: 0)
addSubview(fullScreen)
fullScreen.anchor(top: nil, left: nil , bottom: photoImageView.bottomAnchor, right: photoImageView.rightAnchor, paddingTop: 0, paddingLeft: 0, paddingBottom: 15, paddingRight: 15, width: 30, height: 30)
addSubview(activityIndicatorView)
activityIndicatorView.anchor(top: photoImageView.centerYAnchor, left: photoImageView.centerXAnchor , bottom: nil, right: nil, paddingTop: -15, paddingLeft: -15, paddingBottom: 0, paddingRight: 0, width: 0, height: 0)
setupActionButtons()
addSubview(likeCountButton)
likeCountButton.anchor(top: photoImageView.bottomAnchor, left: likeButton.rightAnchor, bottom: nil, right: nil, paddingTop: 16, paddingLeft: -18, paddingBottom: 0, paddingRight: 0, width: 0, height: 0)
addSubview(captionLabel)
captionLabel.anchor(top: likeButton.bottomAnchor, left: leftAnchor, bottom: nil, right: rightAnchor, paddingTop: 0, paddingLeft: 8, paddingBottom: 6, paddingRight: 8, width: 0, height: 0)
addSubview(viewCount)
viewCount.anchor(top: captionLabel.bottomAnchor, left: leftAnchor, bottom: bottomAnchor, right: rightAnchor, paddingTop: 10, paddingLeft: 8, paddingBottom: 6, paddingRight: 8, width: 0, height: 0)
}
fileprivate func setupActionButtons() {
let stackView = UIStackView(arrangedSubviews: [likeButton, likeCount,commentButton, commentCount])
stackView.distribution = .fillProportionally
addSubview(stackView)
stackView.anchor(top: photoImageView.bottomAnchor, left: leftAnchor, bottom: nil, right: nil, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: 190, height: 50)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Couple of things which might need changing in your code to achieve what you need:
Dont use sizeForItemAt to derive the height of custom cell.
Instead use estimatedItemSize in your viewDidLoad.
Compute the height for the cell depending on the content for the cell in didSet function for post.

Why a navigation bar button item doesn't work when the textview has been resignedFirstResponder()?

Here is an odd one. I have two bar button items, one is cancel and one is done. The done button saves the text in the textview in the coreData and then pops the current view from the navigationController and goes to previous viewcontroller. The cancel button just goes to the previous controller. The whole thing works when the textview is the firstResponder() or the keyboard is up. When the keyboard resigns as the firstResponder, both buttons don't work. As in the just don't do anything. Done button doesn't save the text nor it takes me to previous viewcontroller.
Here is the code for both the buttons:
Done button:
#objc func handleDoneButton() {
print("hello")
if edittaskview.text.isEmpty == true
{
moContext.delete(editnotes!)
}
else
{
editnotes?.sNote = edittaskview.text
}
var error: NSError?
do {
// Save The object
try moContext.save()
print("SAVED")
} catch let error1 as NSError {
error = error1
}
_ = navigationController?.popViewController(animated: true)
}
Cancel button:
#objc func handleCancelButton()
{
_ = navigationController?.popViewController(animated: true)
}
Again, the code in both these functions work when the buttons are tapped only when the textview is the first responder otherwise they don't.
ViewController code:
import UIKit
import CoreData
class editViewController: UIViewController, UICollectionViewDelegate,
UICollectionViewDataSource, UICollectionViewDelegateFlowLayout,
UITextViewDelegate, UIGestureRecognizerDelegate{
var editnotes: addednotes?
var prioritynumber: Int = 1
let moContext = (UIApplication.shared.delegate as!
AppDelegate).persistentContainer.viewContext
var colorArray = [prioritylevels]()
lazy var edittaskview: UITextView = {
let textview = UITextView()
textview.isScrollEnabled = false
textview.font = UIFont.systemFont(ofSize: 16)
textview.backgroundColor = .white
textview.delegate = self
return textview
}()
var clearview: UIView = {
let view = UIView()
view.backgroundColor = .clear
//view.isUserInteractionEnabled = false
return view
}()
let rightBarButton = UIBarButtonItem(title: "Done", style: .done, target: self, action: #selector(handleDoneButton))
let leftBarButton = UIBarButtonItem(title: "Cancel", style: .done, target: self, action: #selector(handleCancelButton))
lazy var priorityCV: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.minimumInteritemSpacing = 0
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
cv.delegate = self
cv.dataSource = self
return cv
}()
let line: UIView = {
let line = UIView()
return line
}()
let reminderView: UIView = {
let reminder = UIView()
reminder.backgroundColor = .white
return reminder
}()
let reminderTitle: UILabel = {
let title = UILabel()
title.text = "Due Date"
title.textColor = .black
title.font = UIFont(name: "Avenir Next", size: 16)
title.font = UIFont.boldSystemFont(ofSize: 16)
return title
}()
let reminderMsg: UILabel = {
let title = UILabel()
title.text = "No Due Date Set"
title.textColor = .black
// title.font = UIFont(name: "Avenir Next", size: 12)
title.font = UIFont.systemFont(ofSize: 12)
return title
}()
let reminderAddBtn: UIButton = {
let btn = UIButton(type: .system)
btn.setTitle("Set", for: .normal)
btn.setTitleColor(.black, for: .normal)
btn.titleLabel?.font = UIFont.systemFont(ofSize: 14)
btn.addTarget(self, action: #selector(handleSetReminderBtn), for: .touchUpInside)
return btn
}()
var textHeightConstraint: NSLayoutConstraint?
override func viewWillAppear(_ animated: Bool) {
adjustTextViewHeight()
}
let datePicker: UIDatePicker = UIDatePicker()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor(red:0.97, green:0.97, blue:0.97, alpha:1.0)
datePicker.addTarget(self, action: #selector(datePickerValueChanged(_:)), for: .valueChanged)
//ColorArray for PriorityCV
colorArray = [prioritylevels(color: UIColor(red:0.00, green:0.78, blue:0.73, alpha:1.0), name: " Low", prioritynumber: 1), prioritylevels(color: UIColor(red:0.00, green:0.78, blue:0.35, alpha:1.0), name: "Medium", prioritynumber: 2),prioritylevels(color: UIColor(red:0.88, green:0.63, blue:0.00, alpha:1.0), name: " High", prioritynumber: 3), prioritylevels(color: UIColor(red:0.96, green:0.28, blue:0.70, alpha:1.0), name: "Urgent", prioritynumber: 4)]
priorityCV.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "cvid")
navigationItem.title = "Edit Task"
self.navigationItem.setHidesBackButton(true, animated: false)
self.navigationController?.navigationBar.tintColor = UIColor.white
navigationItem.rightBarButtonItem = rightBarButton
navigationItem.leftBarButtonItem = leftBarButton
view.addSubview(clearview)
clearview.addSubview(line)
clearview.addSubview(edittaskview)
clearview.addSubview(priorityCV)
clearview.addSubview(reminderView)
reminderView.addSubview(reminderTitle)
reminderView.addSubview(reminderMsg)
reminderView.addSubview(reminderAddBtn)
edittaskview.text = editnotes?.sNote
edittaskview.becomeFirstResponder() //taskview becomes first responder here when the view is loaded.
// view.addSubview(datePicker)
setupViews()
line.backgroundColor = editnotes?.sPriorityColor
let dismissbytap = UITapGestureRecognizer()
dismissbytap.addTarget(self, action: #selector(handleDismissByTap))
dismissbytap.delegate = self
clearview.addGestureRecognizer(dismissbytap) //a clear uiview is added behind all the subviews. this uiview is used to dismiss keyboard when tapped on it.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return colorArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cvid", for: indexPath)
cell.backgroundColor = colorArray[indexPath.row].color
let prioritylabel = UILabel(frame: CGRect(x: view.frame.width / 20, y: 0, width: view.frame.width / 4, height: 30))
cell.addSubview(prioritylabel)
prioritylabel.text = colorArray[indexPath.row].name
prioritylabel.textColor = .white
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.frame.width / 4, height: 30)
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
prioritynumber = colorArray[indexPath.row].prioritynumber
line.backgroundColor = colorArray[indexPath.row].color
editnotes?.sPriorityColor = colorArray[indexPath.row].color
editnotes?.sPriorityNumber = prioritynumber
print(prioritynumber)
}
func setupViews()
{
_ = edittaskview.anchor(line.bottomAnchor, left: view.leftAnchor, bottom: nil, right: view.rightAnchor, topConstant: 2, leftConstant: 0, bottomConstant: 0, rightConstant: 0, widthConstant: 0, heightConstant: 0)
self.edittaskview.contentInset = UIEdgeInsetsMake(2, 8, 4, 8)
self.textHeightConstraint = edittaskview.heightAnchor.constraint(equalToConstant: 80)
self.textHeightConstraint?.isActive = true
self.adjustTextViewHeight()
_ = clearview.anchor(view.topAnchor, left: view.leftAnchor, bottom: view.bottomAnchor, right: view.rightAnchor, topConstant: 0, leftConstant: 0, bottomConstant: 0, rightConstant: 0, widthConstant: 0, heightConstant: 0)
_ = priorityCV.anchor(edittaskview.bottomAnchor, left: clearview.leftAnchor, bottom: nil, right: clearview.rightAnchor, topConstant: 0, leftConstant: 0, bottomConstant: 0, rightConstant: 0, widthConstant: 0, heightConstant: 30)
_ = line.anchor(clearview.topAnchor, left: clearview.leftAnchor, bottom: nil, right: clearview.rightAnchor, topConstant: 0, leftConstant: 0, bottomConstant: 0, rightConstant: 0, widthConstant: 0, heightConstant: 4)
_ = reminderView.anchor(priorityCV.bottomAnchor, left: clearview.leftAnchor, bottom: nil, right: view.rightAnchor, topConstant: 30, leftConstant: 0, bottomConstant: 0, rightConstant: 0, widthConstant: 0, heightConstant: 60)
_ = reminderTitle.anchor(reminderView.topAnchor, left: reminderView.leftAnchor, bottom: nil, right: nil, topConstant: 8, leftConstant: 8, bottomConstant: 0, rightConstant: 0, widthConstant: 100, heightConstant: 20)
_ = reminderMsg.anchor(reminderTitle.bottomAnchor, left: reminderView.leftAnchor, bottom: nil, right: nil, topConstant: 4, leftConstant: 8, bottomConstant: 0, rightConstant: 0, widthConstant: 100, heightConstant: 24)
_ = reminderAddBtn.anchor(reminderView.topAnchor, left: nil, bottom: nil, right: reminderView.rightAnchor, topConstant: 20, leftConstant: 0, bottomConstant: 20, rightConstant: 32, widthConstant: 30, heightConstant: 20)
}
#objc func handleDoneButton() {
print("hello")
if edittaskview.text.isEmpty == true
{
moContext.delete(editnotes!)
}
else
{
editnotes?.sNote = edittaskview.text
}
var error: NSError?
do {
// Save The object
try moContext.save()
print("SAVED")
} catch let error1 as NSError {
error = error1
}
_ = navigationController?.popViewController(animated: true)
}
func textViewDidChange(_ textView: UITextView) {
self.adjustTextViewHeight()
}
func adjustTextViewHeight() {
let fixedWidth = edittaskview.frame.size.width
let newSize = edittaskview.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.greatestFiniteMagnitude))
self.textHeightConstraint?.constant = newSize.height + 15
self.view.layoutIfNeeded()
}
#objc func handleCancelButton()
{
_ = navigationController?.popViewController(animated: true)
}
#objc func datePickerValueChanged(_ sender: UIDatePicker) {
let componenets = Calendar.current.dateComponents([.year, .month, .day, .hour, .minute], from: sender.date)
if let day = componenets.day, let month = componenets.month, let year = componenets.year, let hour = componenets.hour, let minute = componenets.minute {
print("\(day) \(month) \(year) \(hour) \(minute)")
}
}
#objc func handleDismissByTap() {
edittaskview.resignFirstResponder() // Resigning textview as first responder
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
return touch.view == gestureRecognizer.view
}
This does seem odd - and I don't know why the navigation bar buttons are only calling the functions when your text view is active, but...
One way around it is to move your right and left UIBarButtonItem declarations into viewDidLoad() instead of at the class level.
As an aside, you'll get a better animation and keyboard appearance if you move edittaskview.becomeFirstResponder() from viewDidLoad() to viewDidAppear().
I don't know how but instead of creating bar buttons seperately and then assigning them like so self.navigationBarItem.leftbarbutton = leftBarbutton
I decided to construct them using UIBarButtonItem constructor.
self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Cancel", style: .done, target: self, action: #selector(handleCancelButton))
It worked!
Pretty odd to be honest.
Something you could do as well is making the declaration of your UIBarButtonItem a lazy var.
It's getting instantiated with the class. If you make it a lazy var it will get created when you need to use it. If you want to keep it a let and at class level, just do:
override func viewDidLoad() {
super.viewDidLoad()
yourBarButtonItem.target = self
}
Either of these methods will keep the target intact. I was having this same issue.
It's still a weird issue and I think the compiler should yell at you for trying to use self before initialization. It does so when you put self() instead.

UICollectionViewCell Constraint Issues

Look hear for edits
So I have a comments feature in my app that users use to communicate. Each comment has a pic, some text and button that lets you either flag or reply to comments. As seen in the picture below
However as seen in the picture there is a clear problem. If you add too much text it seems to run right over the button. Is there anyway I can prevent this from happening I think it looks really bad.
Below is my sorce code for reference I'm thinking it might be my constraints but I am not entirely sure.
import Foundation
import UIKit
import Firebase
protocol CommentCellDelegate: class {
func optionsButtonTapped(cell: CommentCell)
func handleProfileTransition(tapGesture: UITapGestureRecognizer)
}
class CommentCell: UICollectionViewCell {
weak var delegate: CommentCellDelegate? = nil
override var reuseIdentifier : String {
get {
return "cellID"
}
set {
// nothing, because only red is allowed
}
}
var didTapOptionsButtonForCell: ((CommentCell) -> Void)?
var comment: CommentGrabbed?{
didSet{
guard let comment = comment else{
return
}
// print("apples")
// textLabel.text = comment.content
//shawn was also here
profileImageView.loadImage(urlString: comment.user.profilePic!)
// print(comment.user.username)
let attributedText = NSMutableAttributedString(string: comment.user.username!, attributes: [NSAttributedStringKey.font: UIFont.boldSystemFont(ofSize: 14)])
attributedText.append(NSAttributedString(string: " " + (comment.content), attributes: [NSAttributedStringKey.font: UIFont.systemFont(ofSize: 14)]))
textView.attributedText = attributedText
}
}
let textView: UITextView = {
let textView = UITextView()
textView.font = UIFont.systemFont(ofSize: 14)
textView.isScrollEnabled = false
textView.isEditable = false
return textView
}()
lazy var profileImageView: CustomImageView = {
let iv = CustomImageView()
iv.clipsToBounds = true
iv.isUserInteractionEnabled = true
iv.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleProfileTransition)))
iv.contentMode = .scaleAspectFill
return iv
}()
lazy var flagButton: UIButton = {
let flagButton = UIButton(type: .system)
flagButton.setImage(#imageLiteral(resourceName: "icons8-Info-64"), for: .normal)
flagButton.addTarget(self, action: #selector(optionsButtonTapped), for: .touchUpInside)
return flagButton
}()
#objc func optionsButtonTapped (){
didTapOptionsButtonForCell?(self)
}
#objc func onOptionsTapped() {
delegate?.optionsButtonTapped(cell: self)
}
#objc func handleProfileTransition(tapGesture: UITapGestureRecognizer){
delegate?.handleProfileTransition(tapGesture: tapGesture)
// print("Tapped image")
}
override init(frame: CGRect){
super.init(frame: frame)
addSubview(textView)
addSubview(profileImageView)
addSubview(flagButton)
textView.anchor(top: topAnchor, left: profileImageView.rightAnchor, bottom: bottomAnchor, right: rightAnchor, paddingTop: 4, paddingLeft: 4, paddingBottom: 4, paddingRight: 4, width: 0, height: 0)
profileImageView.anchor(top: topAnchor, left: leftAnchor, bottom: nil, right: nil, paddingTop: 8, paddingLeft: 8, paddingBottom: 0, paddingRight: 0, width: 40, height: 40)
profileImageView.layer.cornerRadius = 40/2
flagButton.anchor(top: topAnchor, left: nil, bottom: nil, right: rightAnchor, paddingTop: 4, paddingLeft: 0, paddingBottom: 0, paddingRight: 4, width: 40, height: 40)
flagButton.addTarget(self, action: #selector(CommentCell.onOptionsTapped), for: .touchUpInside)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
You need to assign textView's right anchor to the button's left one so they got aligned on sides. This would be the correct layout setup for the textView:
textView.anchor(top: topAnchor, left: profileImageView.rightAnchor, bottom: bottomAnchor, right: flagButton.leftAnchor, paddingTop: 4, paddingLeft: 4, paddingBottom: 4, paddingRight: 4, width: 0, height: 0)

Show all cells in UITableView

I have got this table in my swift project
tableView = UITableView()
tableView.dataSource = self
tableView.delegate = self
let tableViewHeight = postTexts.count*200
tableView.estimatedRowHeight = 55
tableView.rowHeight = UITableViewAutomaticDimension
tableView.allowsSelection = false;
tableView.reloadData()
tableView.layoutIfNeeded()
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat{
return 55
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat{
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
let ProfilePicture = UIImageView()
ProfilePicture.image = #imageLiteral(resourceName: "cole")
let username = UILabel()
username.text = posters[indexPath.row]
username.numberOfLines = 0
let postText = UITextView()
postText.text = postTexts[indexPath.row]
postText.isScrollEnabled = false
postText.isUserInteractionEnabled = false
let border = UIView()
border.backgroundColor = UIColor(r: 17, g: 221, b: 219)
cell.addSubview(ProfilePicture)
cell.addSubview(username)
cell.addSubview(postText)
cell.addSubview(border)
ProfilePicture.anchor(cell.topAnchor, left:cell.leftAnchor, bottom: nil, right: nil, topConstant: 15, leftConstant: 14, bottomConstant: 0, rightConstant: 0, widthConstant: 50,heightConstant:50)
username.anchor(cell.topAnchor, left:ProfilePicture.rightAnchor, bottom: postText.topAnchor, right: cell.rightAnchor, topConstant: 20, leftConstant: 13, bottomConstant: 0, rightConstant: 15, widthConstant: 0)
postText.anchor(username.bottomAnchor, left:ProfilePicture.rightAnchor, bottom:nil, right: cell.rightAnchor, topConstant: 0, leftConstant: 15, bottomConstant: 0, rightConstant: 15, widthConstant: 0)
border.anchor(postText.bottomAnchor, left:cell.leftAnchor, bottom: cell.bottomAnchor, right: cell.rightAnchor, topConstant: 20, leftConstant: 0, bottomConstant: 20, rightConstant: 0, widthConstant: 0,heightConstant:1)
cell.layoutIfNeeded()
cell.sizeToFit()
return cell
}
I want my table to show all cells,but it only shows half of them like here
As you see he only shows 2 cells even though there are 4 of them,how can i change it's behaviour to show all cells?
Here are my table constraints
tableView.anchor(PostsDiv.bottomAnchor, left:view.leftAnchor, bottom: nil, right: view.rightAnchor, topConstant: 40, leftConstant: 15, bottomConstant: 0, rightConstant: 15, widthConstant: 0,heightConstant:tableView.contentSize.height+tableView.contentInset.bottom+tableView.contentInset.top)
This is still the same issue from your older posts. Your cells aren't working correctly since you want automatic height in cells but you have the wrong constraints set on your tableView and cell. This is a third repost of your question but here is your answer from Andrea and me:
Swift UITableViewAutomaticDimension is not working
I created nearly the same UI using interface builder.
https://github.com/Hapeki/Example4
I recommend you take a look at this and how AutoLayout works before settings stuff programmatically. The UI is based on my explanation from https://stackoverflow.com/a/42971009/6414904
Demo video:
The cells are automatically sized, seen by the large lorem ipsum text. If you want to make the entire screen scroll you should consider making a headerView for your tableView, but that's out of the scope for this question. In your code you set the tableView height based on the count of your cells * height: let tableViewHeight = postTexts.count*200
, thats is the wrong way to work and it will cause issues after issues. I would highly recommend using interface builder (Storyboards) or if you want some "hybrid" approach you could go for xibs/nibs, where you can make View classes that contain outlets and do some programmatic stuff in it.

Resources