iOS MRC turn arc

Source: Internet
Author: User

First, preface

Project Introduction

Number of objective-c files to convert: 1000 or so.

Development tools: Xcode 8.0.1

Conversion Mode

I am using the Arc conversion feature provided by Xcode itself. Of course you can also manually convert manually, that is not part of this article, and its workload will definitely make you crash.

Second, the conversion process

Code Backup

Before making such a large-scale change, be sure to make a code backup: Copy the code directly locally, or remember the version number on the VCS before changing the code.

Filtering files that do not need to be converted

Identify the third-party libraries referenced in your project that still use manual memory management, or some files that you do not want to convert, add-fno-objc-arc tags to them.

The Xcode auto-conversion tool is only for OBJECTIVE-C objects and only handles objective-c/objective-c++, which is the two files with the suffix. m/.mm, so that the other C + + + corresponding. C/.cpp don't bother.

Perform a check operation

Using the Xcode transform tool Portal:

Clicking Convert to Objective-c arc will enter the check operation entrance,

This step selects which files need to be converted, and Xcode will automatically help you identify which files need to be converted, which can be selected entirely.

When you click the Check button, Xcode helps us to check for errors or warnings in the code that do not conform to the ARC usage rules, and only after all the errors are resolved can you perform a true conversion operation.

Resolve Errors/Alarms

After performing the check operation, a prompt is given:

More than 300 errors, as well as more than 1200 warning messages, are going to cry ...

Errors and warnings are resolved in more detail and are described separately later.

Perform a conversion operation

After all the error is resolved, the following prompt interface will pop up:

The idea is that Xcode will convert your project to use ARC to manage the memory, and all the changed code will be shown in a review interface before it is actually changed. At the same time, when all the changes are complete, Xcode will speak the project target corresponding to the engineering settings using ARC settings (objective-c Automatic Reference counting) will be set to Yes (the warning sign in the upper right corner is telling us that the project already supports arc, but there are files in the project that are not supported):

This is not far from success, victory in sight!

Click the Next button to jump to the review interface, which is similar to using Xcode to submit an SVN confirmation submission interface, as shown in:

This interface lists all the files that require code changes, while being able to directly compare changes in code before and after conversion. To be on the safe side, I chose to take a glance at every file, which gave us a chance to check if we missed a file that can't be converted. Make sure everything is correct, click the Save button in the bottom right corner and everything is done!

Error/Warning resolution

Error

ARC forbids synthesizing a property of an Objective-c object with unspecified ownership or storage attribute

The property attribute must specify a memory management keyword and add the strong keyword to the attribute definition.

ARC forbids explicit message send of ' release '

This is usually done by using a macro definition that contains release, and deleting the macro and the place where the macro is used.

Init methods must return a type related to the receiver type

The reason for the error is that a method in Class A starts with Init and returns a type B, OK, just change the method name.

Cast of C pointer type ' Ivpointer ' (aka ' void ') to objective-c pointer type ' Iflyttsmanager_old ' requires a bridged cast

Cast_pointer_objective-c

This is the toll-free bridging conversion problem, under the arc under the situation to use the corresponding conversion keywords on the line, the article will be specifically described.

Warning

The goal of resolving the warning is to eliminate the danger of code in the warning, since Xcode gives the hint, then every warning message deserves our serious treatment.

Capturing self in this block are likely to leads to a retain cycle

This is a typical block circular reference problem, changing the self in block to use the weak pointer to self.

Using ' Initwitharray: ' With a literal is redundant

Well, it turns out to be unnecessary. Alloc operation, just press the Xcode prompt to delete the alloc:

Init methods must return a type related to the receiver type

It turns out that a method in Class A starts with Init and returns a type B, OK, just change the method name.

Property follows Cocoa naming convention for returning ' owned ' objects

This is because the name of the @property property begins with new, hateful ... The method of modification is to change the corresponding getter method to a name other than the new start:

Arc under the method name if it is new/alloc/init and so on, and is not the initialization method of the class, it should be careful, either error, or warning, the reason you understand.

Block implicitly retains ' self '; Explicitly mention ' self ' to indicate the is intended behavior

This means that the instance variable _selectedmodemarkerview of self is used in block, so the block implicitly retain self. Xcode thinks this may be confusing to the developer, or therefore inherited a circular reference, so warn us to show the use of self in block to achieve block display retain self.

There are two ways to change this warning: ① follow the Xcode prompts and change to Self->_selectedmodemarkerview:

② Direct this warning off warning name: implicit retain of ' self ' within blocks the corresponding clang keyword is:-wimplicit-retain-self

Weak unpredictably set to nil and Weak property ' delegate ' are accessed multiple times in this method Be unpredictably set to nil; Assign to a strong variable to keep the object alive

This is the highest number of warnings in the project, because all delegate properties are weak, and Xcode turns on the two warning settings in the default setting:

Capturing ' self ' strongly in this block are likely to leads to a retain cycle

This is evident in the case of block causing circular reference memory leaks, before the code pits AH! To modify a scenario:

Method parameter of type ' Nserror __autoreleasing ' with no explicit ownership

Needless to say, add the __autoreleasing keyword as prompted in the warning.

The above list of errors and warnings is only a large number, there are many others are not listed here.

In addition, recommend Mattt Thompson God about clang in the name of almost all warning and corresponding error prompt website: http://fuckingclangwarnings.com/, solve warning class problem in the future is much simpler!

Xcode Auto Convert

Keyword Conversion

Xcode automatically converts certain keywords to the corresponding version of Arc.

Retain automatically turns into strong,

Assign keyword turns into weak

The Assign keyword that modifies the Objective-c object or the ID type object is turned into weak,

But the assign of a numeric variable such as a modified Int/bool is not automatically converted to weak,

Keyword deletion

and manual memory management related to several keywords, such as: Release/retain/autorelease/super Dealloc, etc. will be deleted;

If, in addition to the Release/super dealloc statement, the Dealloc method is preserved if other code is dealloc in the method,

If no entire method is removed:

Keyword substitution

The Block keyword is automatically replaced with weak when converting:

@autoreleasepool

NSAutoreleasePool does not support arc and will be replaced with @autoreleasepool:

About being macro commented code

Releasing code using an object defined by a macro

The macro definition is as follows:

12 #define RELEASE_SAFELY(__POINTER) { \[(__POINTER) release]; (__POINTER) = nil; }

When you perform an arc conversion check operation, Xcode will use this macro to error:

Delete the macro and the place where you used the macro.

The code that is commented out by the macro is not processed by Xcode at the time of conversion.

PS: This is quite a bit of a pit, because you simply can't anticipate how many macros are being used in the project, and how much code has been commented out. When you're done with the conversion, you think it's time to do it, but one day, because of a macro opening, you encounter a bunch of new arcs that aren't completely complete. This kind of problem also did not recruit, can only meet one to change one.

ARC and Block

Memory leaks, whether manual memory management or Arc,block circular references, are a daunting issue. In MRC, resolving block circular references only requires the use of the __block keyword, which is slightly more complex to solve with block using arc:

__block keywords

Modify external definition variables within block

As with manual memory management, ARC if you need to modify variables defined outside of block in block, you need to use the __block keyword modifier, such as:

1234 __block NSString *name = @"foggry";self.expireCostLabel.completionBlock = ^(){    name = @"wangzz";};

The name variable in the previous example needs to be modified in the block, so you must use the __block keyword.

The difference between __block in MRC and ARC

When you use the __block keyword-decorated object in a block under Arc, the block retain the object, but the MRC does not retain. This is described in detail in the official document transitioning to ARC Release notes:

In manual reference counting mode, block ID x; Has the effect of retaining X. In ARC mode, block ID x; defaults to retaining X (just as all other values).

The following code has a memory leak in both the MRC and Arc Mycontroller objects:

12345 MyViewController *myController = [[MyViewController alloc] init…];// ...myController.completionHandler =  ^(NSInteger result) {   [myController dismissViewControllerAnimated:YES completion:nil];};

Memory leak issues can be changed in MRC as follows:

12345 MyViewController * __block myController = [[MyViewController alloc] init…];// ...  myController.completionHandler =  ^(NSInteger result) {    [myController dismissViewControllerAnimated:YES completion:nil];};

In arc, however, this is not a change. As we said at the beginning, the Mycontroller.completionhandler block in Arc will retainmycontroller the object, making the memory leak problem still exists!!

There are two solutions to this problem in arc, the first of which:

123456 MyViewController * __block myController = [[MyViewController alloc] init…];// ...  myController.completionHandler =  ^(NSInteger result) {    [myController dismissViewControllerAnimated:YES completion:nil];    myController = nil;};

When the method is finished using Mycontroller in the block, it points to nil. When a pointer with no strong type points to an object pointed to by Mycontroller, the object is freed.

The second solution is to use the weak instead of the BLOCK keyword directly:

123456 MyViewController *myController = [[MyViewController alloc] init…];// ...  MyViewController * __weak weakMyViewController = myController;myController.completionHandler =  ^(NSInteger result) {    [weakMyViewController dismissViewControllerAnimated:YES completion:nil];};

This method avoids the retain of block to Mycontroller object directly.

There is a circular reference relationship

If self has a strong reference to the block, either directly or indirectly, the Self keyword is used in the block, and the self and the Block have a circular reference relationship. At this point, you must define a pointer to self using the __weak keyword, and use that pointer in the block to refer to self:

1234 MessageListController * __weak weakSelf = self;self.messageLogic.loadMoreBlock = ^(IcarMessage * theMessage) {    [weakSelf.tableView setPullTableIsLoadingMore:YES];};

It is important to note that although the weakself in the example above refers to a weak reference to self, the self has a strong reference to the block, and the self's life cycle must be longer than the block, so you don't have to worry about using the weakself pointer in the block. The self that it points to will be freed.

There is no circular reference relationship

The following example:

1234567891011121314 MyViewController *myController = [[MyViewController alloc] init…];// ...MyViewController * __weak weakMyController = myController;myController.completionHandler =  ^(NSInteger result) {    MyViewController *strongMyController = weakMyController;    if(strongMyController) {        // ...        [strongMyController dismissViewControllerAnimated:YES completion:nil];        // ...    }    else{        // Probably nothing...    }};

As stated earlier, The Mycontroller.completionhandler block does not use the Mycontroller object directly, causing a memory leak, so you need to first point to the Mycontroller object with a weak pointer, and then use the weak pointer in the block. But to ensure that the Mycontroller object was not released when the block was executed, At the beginning of the block, a temporary pointer to the strong type is defined Strongmycontroller points to the weak pointer Weakmycontroller, in fact the final result is a strong reference to the Mycontroller object in the block. When the block is destroyed, the Strongmycontroller pointer variable is destroyed and the Mycontroller object that eventually points to it is destroyed. This ensures that the object is present when the object is used, and discards the ownership of the object when it is finished.

Arc and toll-free bridging

The toll-freebridging of the MRC does not involve the transfer of memory management, OBJECTIVE-C (hereinafter referred to as OC) and Core Foundation (hereinafter referred to as CF) each manages their own memory, which can be exchanged directly with each other, for example:

12 NSLocale *gbNSLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_GB"];CFLocaleRef gbCFLocale = (CFLocaleRef)gbNSLocale;

And under Arc, things get a little bit more complicated. Because Arc is able to manage the memory of OC objects, but cannot manage CF objects, CF objects still require us to manage memory manually. When the bridge object is between CF and OC, the problem arises, and the compiler does not know what to do with the OC pointer and the object that the CF pointer points to. At this point, you need to use __bridge, __bridge_retained, __bridge_transfer and other modifiers to tell the compiler how to do it.

__bridge

It tells the compiler that it is still responsible for managing the reference count at one end of the OC, and the developer continues to manage things on the CF side, such as:

1234 CFStringRef cfString = CFStringCreateWithCString(kCFAllocatorDefault, "CFString", kCFStringEncodingUTF8);NSString *ocString = (__bridge NSString *)cfString;CFRelease(cfString);NSLog(@"%@",ocString);

__bridge_retained or Cfbridgingretain

The two functions are the same, but the usage is different.

Tells the compiler that a retain object is required, and the developer is responsible for releasing it at the CF end. This way, if the object is released at one end of the OC, the object will not be destroyed if the developer does not release the object at one end of the CF.

123456 NSArray *ocArray = [[NSArray alloc] initWithObjects:@"foggry", nil];CFArrayRef cfArray = (__bridge_retained CFArrayRef)ocArray;/** 使用cfArray **/CFRelease(cfArray);

__bridge_transfer or Cfbridgingrelease

The effect is the same, but the usage is different.

This keyword tells the compiler bridge that it also transfers ownership of the object, such as:

1234 CFStringRef cfString = CFStringCreateWithCString(kCFAllocatorDefault, "CFString", kCFStringEncodingUTF8);NSString *ocString = (__bridge_transfer NSString *)cfString;//CFRelease(cfString); //不再需要释放操作NSLog(@"%@",ocString);

In the conversion process, we only need to choose the appropriate keywords according to the specific needs.

In addition, the IDs and void * In ARC cannot be converted directly to each other and must be decorated with the appropriate keywords through toll-freebridging.

Arc and Iboutlet

For the Iboutlet attribute should be used strong or weak always have doubts. This is what the official document is about:

From a practical perspective, in IOS and OS X outlets should is defined as declared properties. Outlets should generally is weak, except for those from File's Owner to top-level objects in a nib >>>file (or, I N IOS, a storyboard scene) which should be strong. Outlets That's create should therefore typically be weak.

What a long paragraph of English want to say is: If the nib file constructed view is directly referenced by the controller top-level view, the corresponding Iboutlet property should be strong;

If the view is a child view on the top view, the View property should be weak, because the top view is referenced by the controller using the strong property, and the top view itself holds the view;

If the controller requires a separate reference to a view, or if the controller does not reference a view's parent view, then its properties should also be strong.

Well, in fact, I can say that if you really lazy to distinguish when to use strong, when with weak, then will be the Iboutlet attributes are set to strong it! When the controller is destroyed, the corresponding Iboutlet instance variable is also destroyed, the strong pointer is set to nil, so there is no memory problem.

Reference documents

Transitioning to ARC Release Notes

Managing the lifetimes of Objects from Nib Files

Nib Memory Management

MRC to Arc for iOS

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.