Why aren't my labels displaying in my collection view cells? - swift

I'm trying to set up a collection view programmatically with my views in separate files. It seems that the labels I'm making are not being displayed in the collection view cells. The cells seem fine, and the data that should be in the cells does exist, but it just isn't showing up.
Here's a link to my full project for reference: https://github.com/bronsonmullens/RPG-Dice-Roller/tree/master/RPG%20Dice%20Roller/RPG%20Dice%20Roller
This is my first post on stackoverflow - sorry if the formatting might be off.

You have:
class DiceLabel: UILabel {
let diceLabel: UILabel = {
let label = UILabel()
// ... configure `label` here ...
return label
}()
}
That's pointless and nonsense. You are giving your label another label as a property, and it does nothing for the display of your label, the DiceLabel. Hence your use of DiceLabel is all wrong, because it's just a plain UILabel with no properties set. None of your configurations have any effect. You mean this:
class DiceLabel: UILabel {
override init(frame: CGRect) {
super.init(frame: frame)
// ... configure `self` here ...
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

Related

Any way to opt out of autoresizing permanently?

I'm writing nib-less views in which I use autolayout for all my layout logic. I find myself having to turn off autoresizing with every view I instantiate. My code is littered with a lot of these:
view.translatesAutoresizingMaskIntoConstraints
Ideally I'd like to just
extension UIView/NSView {
override var translatesAutoresizingMaskIntoConstraints: Bool = false
}
and get it over with once and for all, but extensions can't override stored properties.
Is there some other simple way to switch off autoresizing for good?
Well just a suggestion since its annoying to always set that to false, just setup a function with all the shared setups for the UIView and call it every time,
its saves time and its kinda less annoying than trying and setting the values each time,
extension UIView {
func notTranslated() {
self.translatesAutoresizingMaskIntoConstraints = false
//Add any additional code.
}
}
//Usage
let view = UIView()
view.notTranslated()
You can't override this constraints properties because the UIView maybe declared in the IB
translatesAutoresizingMaskIntoConstraints according to apple.
By default, the property is set to true for any view you programmatically create. If you add views in Interface Builder, the system automatically sets this property to false.
imagine if you could override that from an extension that would lead to some conflicts if there was other UIView's that's have the opposite value True || false, so in my opinion:
Apple did this to prevent any conflicts with the views constrains, therefore if you don't like to write it every time just wrap it up in a function.
Please if anyone have additional information, don't hesitate to contribute.
UPDATE: I found this cool answer that could also work, check out the code below.
class MyNibless: UIView {
//-----------------------------------------------------------------------------------------------------
//Constructors, Initializers, and UIView lifecycle
//-----------------------------------------------------------------------------------------------------
override init(frame: CGRect) {
super.init(frame: frame)
didLoad()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
didLoad()
}
convenience init() {
self.init(frame: CGRect.zero)
}
func didLoad() {
//Place your initialization code here
//I actually create & place constraints in here, instead of in
//updateConstraints
}
override func layoutSubviews() {
super.layoutSubviews()
//Custom manually positioning layout goes here (auto-layout pass has already run first pass)
}
override func updateConstraints() {
super.updateConstraints()
//Disable this if you are adding constraints manually
//or you're going to have a 'bad time'
//self.translatesAutoresizingMaskIntoConstraints = false
translatesAutoresizingMaskIntoConstraints = false
//Add custom constraint code here
}
}
var nibless: UIView = MyNibless()
//Usage
nibless.updateConstraints()
print(nibless.translatesAutoresizingMaskIntoConstraints) //false
So simply just create MyNibless instance as UIView and this also open big door to customizations too

UIAppearance overwrites custom textColor on UILabel

I setup UILabel appearance in my app delegate using:
UILabel.appearance().textColor = UIColor.white
I also have a custom UIView subclass that contains a UILabel along with some other elements (omitted here):
#IBDesignable
class CustomView: UIView {
private let descriptionLabel = HCLabel()
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
override func awakeFromNib() {
super.awakeFromNib()
self.setup()
}
private func setup() {
self.descriptionLabel.textColor = UIColor.black
// ... other things not related to descriptionLabel
}
}
If I instantiate CustomView in a storyboard, everything works just fine. If, however, I instantiate it in code, the descriptionLabel is white (appearance color), not black (the color I set). What's going on here? The way I understood it was that if I set a custom color, the appearance color will not be used.
What you're experiencing is simply a matter of the exact timing with which the UIAppearance proxy applies its settings to a new UIView. When are we to suppose it does this? It can't possibly do it before init, because init is the first thing that happens in the life of the UIView. Thus, the order of events is like this:
override init(frame: CGRect) {
super.init(frame: frame)
setup() // black
}
// and some time later, UIAppearance proxy comes along and sets it to white
So your goal is to call setup pretty early in the life of the label — and certainly before the user ever has a chance to see it — but not so early that the UIAppearance proxy acts later. Let's move the call to setup to a bit later in the life of the label:
// some time earlier, UIAppearance proxy sets it to white
override func didMoveToSuperview() {
setup() // black
}
Now we're acting after the appearance proxy has had a chance to act, and so your settings are the last to operate, and they win the day.
We remain in ignorance of how early we could move the call to setup and still come along after the appearance proxy setting has been obeyed. If you have time, you might like to experiment with that. For example, willMoveToSuperview is earlier; if you call setup there (and not in didMoveToSuperview), does that work? Play around and find out!

Custom UIView retained in memory

I am having an annoying memory issue with a custom UIView when trying to add it as a tableView footer in a VC. Here is what I do:
I declare a custom UIView class called tableViewHeader. My footer is supposed to display a logo and some text, so it has 2 global variables (a UIImage View & a TextView) and one init method to initialize this UIView class (i.e., by adding the two subViews and set some constraints).
In my VC, in the TableView's footerForSection method I declare a new tableViewFooter variable, set the sub-views (attach my PNG, etc.)
and return that view.
The code works fine to display the footer but it wrecks havoc on my memory - the moment I run my app and open the VC that contains that tableViewHeader my memory jumps by ~20MB (~ 20% jump) and doesn't get released once my VC is released (I checked, the VC itself gets correctly de-initialized but it doesn't show any drop in memory).
I tested a few things:
Without adding that footerView and opening/ closing the VC doesn't show that 20MB jump, so I am fairly sure that this is caused by this custom tableViewHeader...
I also checked to make sure the UIImage I load from my Assets is not too large but it's only 200Kb. On top the problem is more the fact that the memory doesn't get released after my VC gets released...
I've tried declaring my variables (the tableViewFooter variable and the sub-views within that new class) but that leaves my variables as nil when I try to add them as sub-views...
I am running out of ideas as to what the culprit is/ how to fix it so any help you could give me would be really highly appreciated!
My code is below - thanks in advance!
Francois
My TableFooterView class:
class MessageTableFooterView: UIView {
var shouldUpdateConstraints = true
var logoView: UIImageView!
var explanationTextView: UITextView!
var addFriendBtn: UIButton!
override init(frame: CGRect){
super.init(frame: frame)
logoView = UIImageView(frame: CGRect.zero)
logoView?.autoSetDimension(.height, toSize: 145)
logoView?.autoSetDimension(.width, toSize: 145)
self.addSubview(logoView)
explanationTextView = UITextView(frame: CGRect.zero)
explanationTextView?.isEditable = false
explanationTextView?.isSelectable = false
explanationTextView?.font = UIFont(name: "HelveticaNeue", size: 17)
explanationTextView?.textColor = .darkGray
explanationTextView?.textAlignment = .center
self.addSubview(explanationTextView)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
My tableView viewForFooter Method:
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
if MessageService.instance.savedMsgs.count > 0 {
return nil
} else {
let headerView = MessageTableFooterView(frame: CGRect.zero)
headerView.logoView.image = UIImage(named: "savedMessagesIcon")
headerView.explanationTextView?.text = "Blablabla"
return headerView
}
}

Swift: Reusable UIView in storyboard and sizing constraints

I'm trying to create a reusable UIView in Swift that I can plug into my Storyboard view controllers. My key issue right now is that the reusable UIView "widget" doesn't fully fit into the UIView box in the storyboard. I followed this tutorial to set up the reusable UIView widget
Created a subclass of UIView and a corresponding .xib -- and connected these:
import UIKit
class MyWidgetView: UIView {
#IBOutlet var view: UIView!;
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder);
NSBundle.mainBundle().loadNibNamed("MyWidgetView", owner: self, options: nil);
self.addSubview(self.view);
}
}
In the XIB, which is the interface file corresponding to the code above, I used UIView with Freeform size under the Simulated Metrics, and Scale to Fill under View mode.
In the main storyboard, I added a UIView block (same rectangular shape) and changed the Class to MyWidgetView
It works, but the components I created in the XIB look squished in the actual app, despite the fact that I used layout constraints in both the XIB and also the main storyboard.
See the screenshot. The pink part isn't supposed to appear, since that is just a color of the UIVIew on the main storyboard that I added to test the sizing. That UIView is actually MyWidgetView (after I changed the class in step 3. So in theory, since MyWidgetView == the UIView on the main storyboard, and that UIView has constraints that make it rectangular in the superview, then why is my widget squished? The blue part below should extend all the way right.
The actual view hierarchy loaded from the nib file in your code is added via
self.addSubview(self.view). So, the frame of your self.view actually has no relationship with its parent, i.e. MyWidgetView.
You may choose either adding layout constraints through code or just setting its frame after being added as a subview. Personally, I prefer the latter. In my experiment, the following is what works for me. I am using Xcode 6.4, which I think is not the same one as yours.
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
if let nibsView = NSBundle.mainBundle().loadNibNamed("MyWidgetView", owner: self, options: nil) as? [UIView] {
let nibRoot = nibsView[0]
self.addSubview(nibRoot)
nibRoot.frame = self.bounds
}
}
Alternatively the variable frame can be overridden. This code worked for me when CardImgText was set to files owner for the view.
class CardImgTxt: NSView {
#IBOutlet var view: NSView!
override var frame: NSRect{
didSet{
view.frame = bounds
}
}
override func drawRect(dirtyRect: NSRect) {
super.drawRect(dirtyRect)
// Drawing code here.
}
required init?(coder: NSCoder) {
super.init(coder: coder)
NSBundle.mainBundle().loadNibNamed("View", owner: self, topLevelObjects: nil)
addSubview(view)
}
}
if you are more interested in efficiency than real time updating. Then replace :
override var frame: NSRect{
didSet{
view.frame = bounds
}
}
with:
override func viewDidEndLiveResize() {
view.frame = bounds
}

swift IBDesignable view not show in storyboard

I want to custom a 5-star UIView,also I want it to be render in storyboard. So I decide to use #IBDesignable and #IBInspectable.The following is my code.
import UIKit
#IBDesignable
class RatingView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
setUpView()
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setUpView()
}
func setUpView() {
let imageView = UIImageView(frame:CGRectMake(0, 0, 50,50))
imageView.image = UIImage(named: "star")
addSubview(imageView)
}
}
And then in my storyboard , I pull a UIView into my canvas,and set Custom class to my custom view as RatingView.The compiler starts to compile storyboard file and I just wait for the custom view to be renderd in canvas.Here is the screenshot.
The state is "up to date",but the view has not been renderd.The view is just staying white,what I want to see is the image I add to the parent view.
When I use UILabel instead of UIImageView, the label is renderd in the canvas but not the UIImageView,how can I render my lovely star image in my canvas.(Images.xcassets has star.png file)
use UILabel instead of UIImageView
func setUpView() {
let label = UILabel(frame: CGRectMake(0, 0, 50, 50))
label.text = "text"
addSubview(label)
}
result:
I was trying to do the same exact thing. You need to put the view in a framework. As #Benson Tommy said in the comments take a look at WWDC 2014 session 411.
Here is a link to the session:https://developer.apple.com/videos/wwdc/2014/#411
Here is a link to the transcript of the session: http://asciiwwdc.com/2014/sessions/411