How to implement class swizzling swift? - ios

i have one view.xib file and it's having small container(container view) which holds all the controls like button/textfield, all the events of controls is handle by parent view.xib class file.
My requirement is at one place i need to add/show parent i.e view.xib completed screen. At one more place i need to add only container view. when i add/show container view only, control's associated events/methods doesn't works.
So i thought, if i can change class of container view with parent view.xib's class, my work can be done.
so either suggest me some other solutions or class swizzaling if it's possible to handle in this way.
basically i am adding container view on uitableview cell's container(view) my code for same is as below
if let questionContainerView = cellQuestionView.viewQuestionContainer {
// let questionContainerView = cellQuestionView
cell.viewQuestionContainer.addSubview(questionContainerView)
questionContainerView.translatesAutoresizingMaskIntoConstraints = false
cell.viewQuestionContainer.addConstraint(NSLayoutConstraint(item: questionContainerView, attribute: NSLayoutAttribute.left, relatedBy: NSLayoutRelation.equal, toItem: cell.viewQuestionContainer, attribute: NSLayoutAttribute.left, multiplier: 1, constant: 0))
cell.viewQuestionContainer.addConstraint(NSLayoutConstraint(item: questionContainerView, attribute: NSLayoutAttribute.right, relatedBy: NSLayoutRelation.equal, toItem: cell.viewQuestionContainer, attribute: NSLayoutAttribute.right, multiplier: 1, constant: 0))
cell.viewQuestionContainer.addConstraint(NSLayoutConstraint(item: questionContainerView, attribute: NSLayoutAttribute.top, relatedBy: NSLayoutRelation.equal, toItem: cell.viewQuestionContainer, attribute: NSLayoutAttribute.top, multiplier: 1, constant: 0))
cell.viewQuestionContainer.addConstraint(NSLayoutConstraint(item: questionContainerView, attribute: NSLayoutAttribute.bottom, relatedBy: NSLayoutRelation.equal, toItem: cell.viewQuestionContainer, attribute: NSLayoutAttribute.bottom, multiplier: 1, constant: 0))
cellQuestionView.layoutIfNeeded()
}

I believe what you are trying to do is create a re-usable UIView with your control buttons, that you can use in different view controllers. There is a great tutorial on Youtube entitled iOS Basically: Reusable UIView - Programming in Swift (Part 1).
Basically, you will want to create a .Xib file dedicated to the view that you want to re-use, with all the actions handled by that custom view class. Every time you will want your custom view, you will need to instantiate it from the Xib file and manually add it as a subview onto the container view.
Good luck and happy coding!
-- edit --
Your updated code shows that this will be part of a UITableView and you are trying to add your custom view on top of a UITableViewCell. You should instead instantiate a custom UITableViewCell and register it as reusable with the table view. This tutorial should guide you on doing just that: Custom UITableViewCell Tutorial - TableView with Images and Text in Swift
You can define your #IBAction in your custom table cell, and attach your button selectors to your action in your custom cell's nib.
Cheers!

Related

NSLayoutConstraint defined in code and bottom Layout Guide deprecated in iOS 11

I have a viewController holding a constraint like this one:
self.subviewConstraint = NSLayoutConstraint(item: self.subviewConstraint,
attribute: .bottom,
relatedBy: .equal,
toItem: self.bottomLayoutGuide,
attribute: .bottom,
multiplier: 1,
constant: 0)
and I'm being shown this warning:
'bottomLayoutGuide' was deprecated in iOS 11.0: Use view.safeAreaLayoutGuide.bottomAnchor instead of bottomLayoutGuide.topAnchor
I'm only finding examples for setting anchors instead of NSLayoutConstraints like this, and I don't fully understand this warning... "use view.safeAreaLayoutGuide.bottomAnchor instead of bottomLayoutGuide.topAnchor"? How is that the bottom anchor of the safeAreaLayoutGuide matches the top anchor of the of the bottomLayoutGuide? Where could I find a good graphical explanation of this?
How should I correctly rewrite my constraint to keep its current behaviour?
TopLayoutGuide and bottomLayoutGuide are deprecated since iOS 11.
You could update your code with this, taking advantage of the new NSLayoutAnchor:
self.subviewConstraint = self.subviewConstraint?.firstItem?.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor)
or you can use the initializer of NSLayoutConstraint as in your question:
self.subviewConstraint = NSLayoutConstraint(item: self.subviewConstraint?.firstItem as Any,
attribute: .bottom,
relatedBy: .equal,
toItem: view.safeAreaLayoutGuide,
attribute: .bottom,
multiplier: 1,
constant: 0)
Note that I've changed your self.subviewConstraint parameter to self.subviewConstraint.firstItem instead, within the NSLayoutConstraint initialization method, because you were using the NSLayoutConstraint as the item.
I suppose this is some kind of typo you made.
Here you can find some good graphical explanation of the new SafeArea behaviour in iOS 11 and above:
iOS Safe Area - Medium.com
Additionally, you said "I'm only finding examples for setting anchors instead of NSLayoutConstraints", but I want to make it clear that the constraint(equalTo:) method of NSLayoutAnchor returns an NSLayoutConstraint. (Apple NSLayoutAnchor documentation)

Swift4 issues : change Nslayoutconstraint programmatically

I would like to change position of UITextfield txtAmount NSLayoutConstraint programmatically from its top to bottom of collection view to bottom of image view. All views are embed in a ui view.
Old constraint is dragged and mapped from storyboard to view controller.
New constraint constr is to be created programmatically.
When it comes to implementation and execution, it says
When added to a view, the constraint's items must be descendants of that view (or the view itself). This will crash if the constraint needs to be resolved before the view hierarchy is assembled.
'Unable to install constraint on view. Does the constraint reference something from outside the subtree of the view? That's illegal.
Would you please tell me any guidelines for such modification ? I embed the UI elements in an embedded UIView because of scrollview I have used.
let constr = NSLayoutConstraint(item: txtAmount, attribute: .top, relatedBy: .equal, toItem: imageView, attribute: .bottom , multiplier: 1, constant: 0)
IETypeList.removeFromSuperview()
uiviewType.removeFromSuperview()
txtAmount.addConstraint(constr)
txtAmount.removeConstraint(constraintPo)
you are adding constraint to the txtAmount whereas you should've added it to the view which actually contains txtAmount and another view referenced in this constraint, i.e. imageView. Let's name this view which contains them superview.
let constr = NSLayoutConstraint(item: txtAmount, attribute: .top, relatedBy: .equal, toItem: imageView, attribute: .bottom , multiplier: 1, constant: 0)
IETypeList.removeFromSuperview()
uiviewType.removeFromSuperview()
txtAmount.removeConstraint(constraintPo)
superview.addConstraint(constr)
But this is not recommended way since iOS 8. As the docs say, you should set the constraint isActive (read this) property to true instead, and iOS will add them to relevant views:
IETypeList.removeFromSuperview()
uiviewType.removeFromSuperview()
constraintPo.isActive = false
constr.isActive = true

ios swift 3 - UIAlertController width

Is there anyway to create a custom alertController that fit the width of the screen ?
I tried several things before asking this question
one of them is :
let width:NSLayoutConstraint = NSLayoutConstraint(item: alertController.view, attribute: NSLayoutAttribute.width, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: view.bounds.width )
alertController.view.addConstraint(width)
But this line of code always makes a horizontal space between my alertController and the Screen.
Here is what I currently find in the Apple documents:
Appearance of Alert Views:
You cannot customize the appearance of alert views.
This disappoints me as I think the message text in alert views is too small for many users. DrPatience, in a comment above, suggests a possible workaround.
Alert Views

Dynamic number of elements in TableViewCell

I need to add labels one after another vertically and their number is dynamic. For now it works fine with this code:
let numUnitsLabel = UILabel(frame: CGRectZero)
numUnitsLabel.text = units
numUnitsLabel.font = UIFont.boldSystemFontOfSize(28)
numUnitsLabel.textColor = UIColor.redColor()
numUnitsLabel.translatesAutoresizingMaskIntoConstraints = false
cell.contentView.addSubview(numUnitsLabel)
let topConstraint = NSLayoutConstraint(item: numUnitsLabel, attribute: .Top, relatedBy: .Equal, toItem: cell.contentView, attribute: .Top, multiplier: 1, constant: 8 * CGFloat(i+1) + CGFloat(i*25) + CGFloat(i*20) - 5)
let rightConstraint = NSLayoutConstraint(item: numUnitsLabel, attribute: .Trailing, relatedBy: .Equal, toItem: cell.contentView, attribute: .Trailing, multiplier: 1, constant: -10)
cell.contentView.addConstraints([topConstraint, rightConstraint])
The cell is drawn fine. But when I add new item in the list and call tableView.reloadData the old labels are "remembered" and they are over new ones. The newly added object is put in the first place in the array and they are like one over another... Maybe my approach is bad, but if you have any suggestions please advice me.
Remember that cells are re-used, so however a cell was prepared previously, it still has all of that state. In particular, its view hierarchy (added subviews) remain. The reason for this is generally a layout of a Table Cell stays the same, and only its content is meant to be re-set in cellForRowAtIndexPath.
You're using an anti-pattern, first of all, which is why you're running into difficulty.
If you really want to clear out and re-layout the cell, remove all subviews explicitly, every time, e.g.:
https://techfuzionwithsam.wordpress.com/2014/12/23/what-is-the-best-way-to-remove-all-subviews-from-parent-viewsuper-view/
I suspect though, (admittedly this isn't CodeReview) that your design is flawed. Generally table cells don't need to grow in height with dynamic count of internal elements. You may need nested tables (!!), really just a single multi-line UITextView in each, or a table structured by sections with custom section header views.

Multiple UILabel at the same line in UIStoryboard

If there are multiple UILabels in one UIStoryboard, and they have the same centerY, which means they are at the same line. How can I use autolayout to let them fit in different screen? I hope these UILabels have same font size.
You need to add constraints. There are a couple of ways to add constraints.
If you go to the storyboard you will see a rectangle in between 2 vertical lines. If you click the the view you want to add constraints too (Like the UIView you added) and click that rectangle box thing It gives you options to add constants to the left, right, top, bottom of the view. If you click on the dropdown menu it gives you a list of views around the view your adding constraints too so that you can add constraints relative to that view.
Another way to add constraints is clicking the triangle button in between 2 vertical lines and selecting the option "add missing constraints". Auto layout will then try and determine the best constraints to add automatically.
To delete or modify constraints you can click the "show size inspector" (looks like a ruler) and in the constraints section you should see some constraints if you have added any. You can click and delete them or edit them.
Another option is adding constraints programmatically (below is an example of adding constraints to an image view in a stack view in swift):
let trailingConstraint = NSLayoutConstraint(item: imageView, attribute: NSLayoutAttribute.Trailing, relatedBy: NSLayoutRelation.Equal, toItem: self.stackView, attribute: NSLayoutAttribute.Trailing, multiplier: 1, constant: -5)
let leadingConstraint = NSLayoutConstraint(item: imageView, attribute: NSLayoutAttribute.Leading, relatedBy: NSLayoutRelation.Equal, toItem: self.stackView, attribute: NSLayoutAttribute.Leading, multiplier: 1, constant: 5)
self.stackView.addArrangedSubview(imageView)
self.stackView.addConstraint(trailingConstraint)
self.stackView.addConstraint(leadingConstraint)

Resources