After completing the learning of MVVM/RAC a few months ago, I have been quietly reconstructing the project code recently, writing a lot of code. After a period of time, I found that my code style and code quality have been greatly improved. In the past few years, I was in charge of iOS client in a small company, and then I was in charge of client development. I was distracted by messy things, so I didn’t write too much code until last year. I have been working in the new company for more than half a year, and now I only play a small role in writing code, so I spend most of my energy on writing business code and learning messy technology in my spare time.

Last month, except for special take time and effort to reconstruct and there was a need to add the function of the module, the historical factors due to the project code is more, the first thing do tend to be refactoring code, find a lot of code written before didn’t notice when things much more special, such as global variables to use; Methods without a sense of hierarchy, random addition; Without understanding the business, functions are implemented by patching. So I decided to write an article to share with you a specific summary of some matters needing attention in my own practice.

Reducing object properties

This is one of the easiest areas to improve the quality of your code. A lot of code looks messy at first glance, with dozens of different object variables defined in it, making it inexplicably impossible to separate different logic from one another. One is that the definition isn’t right, so many puzzling internal variables are exposed in header files, leaving external callers with no idea which methods public can operate on. In fact, in my own refactoring experience, most of these can be replaced with local or __block variables.

1. Expose as few variables or methods as possible in the header file and instead use extension or category in a. M file or a dedicated private header file

Expose as little information as possible in the header file, and don’t expose anything unnecessary




In extension of m file, it defines conforms protocol and object property. Getter /setter is used to define the definition of object property.




2. Use local variables or __block variables instead

There is no need to say more about local variables, and you need to think clearly when writing code. After writing, you must check the review before committing, even if you are responsible for your own code quality, code review often fails to check out redundant or abandoned code. Don’t add a redundant object properties, leaving no comment out code, leaving no use code, these are the basic skills, but many developers just can’t do that, or to write code without love, so a lot of abandoned code, I refactor the code, although the business is not familiar with, but most of the modules can delete the one over ten of the code and a large number of object properties, This is a simple lack of attention.

This is one of my biggest grieves about Android development: using __block variables. It’s a damn good feature.

Here, for example, we’re passing back some variables when we use a block




In this case, I need to record the top coordinates of the headerView at the start of a PAN gesture. After RAC, I use the __block variable to record the value of the global variable




3. Circular references can be avoided whenever possible

One of the things that developers tend to miss is that when using the _XXX object variable in a block, the block retains the self pointer, which can result in a circular reference. So by using local variables, you can nip this problem in the bud.

Reduce and modularize object messages

1. Reduce object messages

Block and RAC, or Blockskit, allow us to hook the target-action model into blocks. The UI and action code can be used together, making the whole logic more compact. I finally don’t have to jump around looking at code. And the other thing is that in your daily development, if you’re writing any protocol or passing target/selector, try to use blocks instead, and trust me, that makes your code a lot easier to read.

2. The modular

Use “#pragma mark-xxx” to split the boundaries between different logic and make the whole document read more structured. Another shortcut that I use most often now is to set Xcode. Change Ctrl + 6 to display the document structure to Command + J, search to quickly jump to the corresponding message and module. Try to avoid the document structure showing more than two screens, which is a bit too much, you must consider reconfiguration.

Personally, I usually divide modules into life Cycle, UI helper, datasource/delegate, module divided according to function, etc. The following is the document structure of a ViewController THAT I recently reconstructed




MVVM && RAC

By the way, MVVM does not necessarily need RAC, but data Binding is indispensable. In iOS, it is also known as KVO. I recommend you to try it. Even the Android SDK had to introduce this feature. This will not reduce the amount of code, but will definitely simplify the complexity of development logic. No need to rewrite the -setxxx: method to update a bunch of unrelated UIs. We’ll talk about new ones later. RACObserver is based on KVO and is called synchronously, so the impact on performance is limited and there is no problem with the order of calls. So I dare to use data Binding in list development, and after practice, it’s ok, it doesn’t affect the user experience.

UI development

1. Rewrite setter methods and Code Block Evaluation C Extension syntax

For example, in -viewDidLoad, as a logical entry, the code is smaller but clearer, as follows:




Then override the getters of bgView, including the View and frame methods ({… }) syntax makes code structured and hierarchical:




2. Development of complex UI

Sometimes when we develop a business, the product requirements are very complex. The result is a very long code with a cool UI and all sorts of well-thought out logic, and most of our work is faced with this kind of problem. About this problem, my solution, combined UI/Custom View/Child View controller to solve.

(1) Combined View

The concept is borrowed from Android. When I looked at the code in the project during reconstruction, I found that people were not very strong about this concept when they used it to do UI. I felt that they didn’t understand UIView view hierarchy enough. For example, in a complex UI, all the subviews are piled directly onto the super view. As a result, it is very difficult to adjust the frame of the subview. My personal approach is to first slice up a complex UI, from left to right or from top to bottom, and put UI elements on top of different Container Views. Then combine those Container Views and put them on top of a Super View. The benefits are obvious. It’s not so strenuous to read. The second is that it’s much easier to calculate coordinates or set constraints, because when you adjust a UI element, you only have to think about its coordinate relationship with the container View that contains it, rather than having to do a lot of tedious calculations associated with the outermost Super View. Moreover, it can make full use of UI tools such as Auto Layout and AutoresiziingMask, which will be very convenient to use. Plus, with the RACObserver tool, you can easily update the UI based on data.

For example, I reconstructed a page in our project some time ago. The home page list has high performance requirements. It is not implemented using Auto Layout, but not using Auto Layout is not a reason not to write it cleanly.




So this is my layerization of a UITableViewCell, the outermost container view consists of icon view, right view, bottom view, And the Right Container view is a combination of sub Container views, right Top View, right middle view, right Bottom View, The specific UI elements are placed in these Sub Container Views. Init/LayoutSubViews only need to maintain the relationship between self and the Container View, and the UI elements that display data only have coordinates with the Sub Container View. Let’s look at the code implementation of the Right Container View:




In terms of performance, thanks to iOS, we do not have the problem of performance lag in Android page hierarchy, rest assured to layer the UI

(2) custom view

Use Custom View subclassing for UI that is complex and relatively independent or reusable. For a simple presentation UI, we can simply do this with a composite View. But sometimes, we will encounter some animation, logic is more complex, this time to use the combined View to achieve, on the one hand, easy to confuse the logic, the document structure of the file will become very complex, simply put, the object of a lot of messages. At this time, we can use the Custom View to implement, in fact, this is also a composite view, but we are the composite view into a class, only a small amount of exposure to external calls. If the custom view appears in multiple business module, so it is necessary to use a separate file to accommodate this class, if is only one of this module is used, it can write directly in the business module file, it is not necessary to a single file for all the classes, we as the “inner class” to make.

When to use a Custom View instead of a combined view, I think for a long time, you think the combined view code is very messy, please feel free to wrap as a Custom View on the line. Some of the problems I’ve encountered recently are when I’m using UICollectionView to do part of the UI, and there are a lot of other UI elements, so I’ll write a Custom View. For example, the following file, a slide left and right to view the image UI using PhotoView custom View packaging, internal use of UICollectionView to achieve a part of the relatively independent module, this time the control can actually be packaged as a relatively independent module, I think subclasses are more appropriate.




(3) container view controller

This is a usage that many developers are not familiar with or use very much, but it is very useful in real business and can greatly improve development efficiency. For this part of knowledge is not familiar, you can refer to my previous blog: blog.csdn.net/colorapp/ar… . For businesses with relatively independent business logic and lifecycle requirements, use the Child View Controller for packaging. If the Parent View Contrller is very close to the Child View Controller, Use the View Model and block to connect the Parent View Controller to the Child View Controller.

There are many advantages of using Child View Controller to develop UI instead of custom View. Personally, I think the biggest advantage is the convenience of using view Controller lifecycle and View Controller Hierarchy. Do something in -ViewwillAppear /-viewDidDisappear, or get the UINavigationController pointer directly, etc. Before method is commonly the View Controller corresponding to the method of life cycle call the custom View passed the self. The navigationController pointer to the custom View, etc. So not only can you wrap uI-related code into this Child View Controller, but you can also put network requests, data processing and all of that logic into the Child View Controller, In this way, you can avoid the view Controller that always exceeds 1K rows.

After using MVVM, there is a more beneficial use, such as when some common data, before we are passing objects to pass around, such a problem is very prone to confusion, this time we are passing ViewModel can avoid this problem, ViewModel is responsible for both network requests and data processing, All the parent View Controller and Child View Controller need to do is bind the ViewModel.

Auto Layout/Masonry

On some non-list pages that require less performance, we can use Auto Layout to develop the UI extensively, taking full advantage of the ABILITY of the UI to adapt to the data without the need to adjust the UI in the Container View. There was a time when I didn’t want to develop iOS at all for the simple reason that the layout and visibility of Android development is very convenient, combined with a great tool like AS, I feel AS efficient AS iOS. I started using Auto Layout only after the project’s minimum support was changed to iOS6. Although it was a bit of a struggle, I felt it was a relief for UI development.

The advantage of this is that once you set the UI data, you don’t have to worry about updating the UI, and the world is instantly clean… Here is my simple example, combined with ({… }) syntax and RAC, we can use the simplest name such as label to set data on the UI, which is definitely a relief for us to develop the UI.







Auto Layout:




2. Animation problems

3. Problem of multi-line UILabel

On iOS7 and below, UILabel displays multiple lines of text. You need to set UILabel’s preferredMaxLayoutWidth to a fixed value to display multiple lines of text. You don’t need to set this after iOS8.




4. Problems with UIScrollView and constraint ambiguity and other issues

Refer to my article: blog.csdn.net/colorapp/ar…

In this area, MY suggestion is to choose the implementation mode according to the specific problem: Whether it is Spring & Structs, Auto Layout, which is relatively simple and quick to solve the problem, do not have to be fixed in one behavior, especially when the development of the page has a lot of animation.

And for the pinyin naming code, can call the shots, do not hesitate to open it. Here to spit out a slot, before the company has such a brother, not I recruit come in, the boss forced me.

Take advantage of OC’s new syntax

For example, we can print numbers using @(XXX), define enums using typedef NS_ENUM, use instanceType instead of ID, and so on. IOS 9 has been released, and OC has some new syntax, so go learn to use it more.

JSON data processing

Novice users are often slightly confused by this, such as when the server returns data in the wrong format, including NULL, which can easily cause the project to crash. Mantle can be used to solve this problem. Many brothers use it, but I have never used it myself. I wrote a small framework on Github, github.com/lihei12345/… This is also used in our project with good effect. When it is used to parse data, it verifies the data type and whether it is NULL, etc., to ensure the correctness of the parsed data type. You can also set some defaults for cases where keys may not exist.

Here’s an example:




block

Using blocks instead of delegates, which goes without saying, makes the code much more compact, reduces the number of messages in the file, and most importantly, makes the relationship less tight. The protocol implementation should only be considered if there are a large number of delegate methods, when too many blocks can make reading difficult.

Also, if you’re passing target/selector, try to use blocks as well, because it’s not easy to read and look up.

Submit code

This is very important because during development, you often need to compare the previous code to ensure that your changes are correct. If there are some minor problems, you can also find the historical version.

Commit as soon as a relatively complete requirement is completed. It’s a good habit to commit small commits.

It takes a lot of time to do a good PR code review. If possible, it is better to hold a summary meeting for each version.

RAC encapsulates network requests

The returned signal avoids multiple side effects, but does not use replay/replayLazily because Dispose is not called.




Combine RACCommand with takeUntil: to encapsulate a request that can cancel.

Copyright notice: This article is the blogger’s original article, shall not be reproduced without the permission of the blogger.