One, foreword
Although I had wanted to write such a series for a long time, I didn’t put it into practice. Starting now, this series will document the problems I encountered with my project, some tips I didn’t know before, etc.
Second, the problem of
2.1 Remove warnings in Pod files
As an OCD, seeing a warning makes me uncomfortable. I didn’t know that warnings in a Podfile could be ignored until I found that they were missing entirely. I had added this configuration to my Podfile:
inhibit_all_warnings!
Copy the code
2.2 After r. swift is introduced, a script conflict is displayed
In the past, we could have told Xcode to give a Warning with OC:
#warning
Copy the code
However, in the Swift project code, this method is invalid, of course, Swift has a new solution:
Click On New Run Script Phase as shown in the picture, then add the following Script code to the added Run Script:
TAGS="TODO:|FIXME:"
echo "searching ${SRCROOT} for ${TAGS}"
find "${SRCROOT}" \( -name "*.swift" \) -print0 | xargs -0 egrep --with-filename --line-number --only-matching "($TAGS* \ $"). | perl -p -e "s/($TAGS)/ warning: \$1/"
Copy the code
FIXME:&TODO:
Xcode
R.swift
.swift
Pod
TAGS="TODO:|FIXME:"
echo "searching ${SRCROOT}/ Project engineering document original name for${TAGS}"
find "${SRCROOT}/ Project file name" \( -name "*.swift" \) -print0 | xargs -0 egrep --with-filename --line-number --only-matching "($TAGS* \ $"). | perl -p -e "s/($TAGS)/ warning: \$1/"
Copy the code
2.3 Use UIScrollView layout directly in StoryBoard
I have become an IB party recently, ha ha!
The reader who hasn’t tried this will think there’s nothing wrong with it. Read on:
Drag a UIScrollView into the controller with Safe areas for the top, bottom, left, and right constraints. Just like the first time I used it, put a UIView directly into the UIScrollView and constrain it to be equal to the top, bottom, left, and right boundaries of the parent view.
UIScrollView
In real development, the final content of the page must be determined, so you can push back the layout of UIScrollView based on the interface. However, as in the illustration above, I and some readers will get annoyed if I keep showing you layout errors. The solution is simple:
Add the content view’s width and height constraint to UIScrollView directly, and then set the height constraint’s priority to less than 1000.
Also, you can set the interface of the controller to Freeform, which is very convenient for some off-screen interface.
2.4 Memory Leakage
Recently, a tripartite memory leak detection tool was imported into wechat.
MLeaksFinder
It is found that there are many memory leaks in the code. After some investigation, here is a summary of common and uncommon memory leaks.
Against 2.4.1 common
- Closure loop reference
// A method used to set the navigation back button
self.setUseCommonNavigationBackButtonWithHandler { (_) in
self.navigationController? .popViewController(animated:true)}Copy the code
Absolutely most readers will avoid this question, but I found a variation:
let vc = UIViewController()
vc.setUseCommonNavigationBackButtonWithHandler { (_) invc.navigationController? .popViewController(animated:true)}Copy the code
Vc and self are the same thing here.
- Does not free the object holding the object to be freed
Scenario: A singleton holds an external object that needs to be released
In our project, we use SVProgressHUD to do the loading. There is a method to set the container view of the loading control:
+ (void)setContainerView:(nullable UIView*)containerView;
Copy the code
The project configates the view of the current controller as a container view, which is then held by the SVProgressHUD singleton. When the controller pops, the view cannot be freed because it is held by the singleton.
- Object loop holding
Scenario: A child controller holds a parent controller
For some interfaces that need to add a child controller to the controller, click on the child controller and then push, but because the parent controller is really the one that needs to be pushed in this scenario, the parent controller is often passed to the child controller.
If you accidentally declare a property that strongly holds the parent controller, you create a circular hold. Weak holding parent controller is correct.
- Listeners and notifications need to be removed
That’s nothing to say, not found in the project, just mentioned
2.4.2 Uncommon
Uncommon here is defined as previously unknown to the author
- WKUserContentController removes position
Scenario: WKWebView interacts with JS
The WKUserContentController instance does not need to be deinit when it is added.
At present, viewWillAppear and viewWillDisappear are added and removed respectively.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
userContent.add(self, name: "xxx")}override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
userContent.removeScriptMessageHandler(forName: "xxx")}Copy the code
- UIAlertController memory leak directly simulates scenario code
class DetailViewController: UIViewController {
var alertController: CustomViewController!
override func viewDidLoad(a) {
super.viewDidLoad()
alertController = CustomViewController(title: nil, message: nil, preferredStyle: UIAlertControllerStyle.actionSheet)
let textAction = UIAlertAction(title: "Photos", style: UIAlertActionStyle.default) { (action:UIAlertAction) in
// Where the problem is
self.title = "Test"
}
alertController.addAction(textAction)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
present(alertController, animated: true, completion: nil)}deinit {
print("DetailViewController init")}}Copy the code
The DetailViewController holds the alertController
The alertController adds the textAction and holds it
The textAction event closure uses self, so it holds the DetailViewController
A circular reference ring is formed, GG.
The solution is also simple: use weak in the closure.
2.5 Static distribution implemented by the Swift protocol by default
See the protocol default implementation in ignore subclasses that does not participate in dynamic dispatch
Here the scenario in my project is to define a protocol to control whether the current controller can slide back
protocol NavigationControllerGestureAble: NSObjectProtocol {
var isCanSlidePop: Bool { get}}extension UIViewController: NavigationControllerGestureAble {
// here @objc needs to be noticed
@objc var isCanSlidePop: Bool {
return true}}... The rest of the slightlyCopy the code
The rimmer argument is that ture, because OC has no calculated properties, is really just a syntactic sugar for set&get methods. So we need to add @objc here (that’s how I understand it), so we’ll just override this in the controller we want to shut down and return false.
Three, afterword.
There’s a new hole…