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…