A, safeArea

  1. automaticallyAdjustsScrollViewInsets to contentInsetAdjustmentBehaviorWith iOS 11, Apple scrapped itUIViewControllerautomaticallyAdjustsScrollViewInsetsProperty, instead ofUIScrollViewcontentInsetAdjustmentBehaviorProperty to replace it.
// OC
@property(nonatomic,assign) BOOL automaticallyAdjustsScrollViewInsets API_DEPRECATED_WITH_REPLACEMENT("Use UIScrollView's contentInsetAdjustmentBehavior instead", ios (7.0, 11.0), tvos (7.0, 11.0)); //swift @available(iOS, introduced: 7.0, deprecated: 11.0) the open var automaticallyAdjustsScrollViewInsets: Bool / / Defaults to YESCopy the code

If you don’t have a startup image for the iPhone X in your project, you’ll notice that the top and bottom parts are black, and that’s the safe zone. To adapt the iPhone X screen, the first step is to add a startup image.

Second,UITableViewAutomatic altitude calculation

In 11 of the iOS, UITableView estimatedRowHeight, estimatedSectionHeaderHeight, estimatedSectionFooterHeight are open by default. What a pleasant surprise.

@property (nonatomic) CGFloat rowHeight;             // default is UITableViewAutomaticDimension
@property (nonatomic) CGFloat sectionHeaderHeight;   // default is UITableViewAutomaticDimension
@property (nonatomic) CGFloat sectionFooterHeight;   // default is UITableViewAutomaticDimension
@property (nonatomic) CGFloat estimatedRowHeight NS_AVAILABLE_IOS(7_0); // default is UITableViewAutomaticDimension, set to 0 to disable
@property (nonatomic) CGFloat estimatedSectionHeaderHeight NS_AVAILABLE_IOS(7_0); // default is UITableViewAutomaticDimension, set to 0 to disable
@property (nonatomic) CGFloat estimatedSectionFooterHeight NS_AVAILABLE_IOS(7_0); // default is UITableViewAutomaticDimension, set to 0 to disable
Copy the code

Step 1

In our app, the home page of the UITableView list is manually calculated row height, suddenly appeared in the past only automatic calculation of row height will appear the phenomenon of scroll bar jump, add observer to the TableView contentSize, sure enough, has been changing. And here’s why.

Stomp Pit 2 (Update)

When I used MJRefersh, there was a bug in the code itself, which was not found before. IOS 11 helped me find this problem.

/ / tableView Settingslet footer = MJRefreshAutoFooter(refreshingBlock: {  [weak self] in
    if let strongSelf = self {
        if letblock = strongSelf.footerBlock { block() } } }) footer? . TriggerAutomaticallyRefreshPercent = - 20 tableView. Mj_footer = footer / / request ending reprocessing (error) models. Append (requestModels)ifModels. The count < pageSize {/ / there is a bug tableView. Mj_footer. EndRefreshingWithNoMoreData ()}else{tableView.mj_footer.state =.idle} tableView.reloadData()ifRequestModels. Count < pageSize {/ / repair bug tableView. Mj_footer. EndRefreshingWithNoMoreData ()}else {
    tableView.mj_footer.state = .idle
}
models.append(requestModels)
tableView.reloadData()
Copy the code

In the code above, there was also an implicit problem before iOS 11, which was that the tableView footer could never be marked as no more data, and even if there was no data, the user would still initiate a request after the dropdown. In iOS 11, the contentSize and contentOffset of tableView changes are still triggered when the row height is estimated and interactions occur at the bottom. RefreshingBlock and reloadData of the tableView are both triggered, causing the last page of data to fall into a loop request.

If there are events that are triggered by listening for contentSize and contentOffset changes in the tableView, it is best to turn off the automatic row height calculation in the tableView to avoid problems.

IPhone X*** (serious) ***

1. Obtain the network status in the status bar

The iPhone X is known for its “beautiful” bangs and changes to its status bar. This also caused a problem with the original API that fetched the network status from the status bar view, causing a flash back.

UIApplication *app = [UIApplication sharedApplication]; NSArray *children = [[[app valueForKeyPath:@"statusBar"] valueForKeyPath:@"foregroundView"] subviews];
int type = 0;
for (id child in children) {
    if ([child isKindOfClass:NSClassFromString(@"UIStatusBarDataNetworkItemView")]) {
        type = [[child valueForKeyPath:@"dataNetworkType"] intValue];
    }
}

switch (type) {
    case 1:
        return @"2G";
    case 2:
        return @"3G";
    case 3:
        return @"4G";
    case 5:
        return @"WIFI";
    default:
        return @"Unknow";
        break;
}
Copy the code

However, you can still use AFNetworking to get network status:

SCNetworkReachabilityContext context = {0, (__bridge void *)callback, AFNetworkReachabilityRetainCallback, AFNetworkReachabilityReleaseCallback, NULL};
SCNetworkReachabilitySetCallback(self.networkReachability, AFNetworkReachabilityCallback, &context);
SCNetworkReachabilityScheduleWithRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes);

switch (self.networkReachabilityAssociation) {
    case AFNetworkReachabilityForName:
        break;
    case AFNetworkReachabilityForAddress:
    case AFNetworkReachabilityForAddressPair:
    default: {
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0),^{
            SCNetworkReachabilityFlags flags;
            SCNetworkReachabilityGetFlags(self.networkReachability, &flags);
            AFNetworkReachabilityStatus status = AFNetworkReachabilityStatusForFlags(flags);
            dispatch_async(dispatch_get_main_queue(), ^{
                callback(status);

                NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
                [notificationCenter postNotificationName:AFNetworkingReachabilityDidChangeNotification object:nil userInfo:@{ AFNetworkingReachabilityNotificationStatusItem: @(status) }];


            });
        });
    }
        break; } static AFNetworkReachabilityStatus AFNetworkReachabilityStatusForFlags(SCNetworkReachabilityFlags flags) { BOOL isReachable = ((flags & kSCNetworkReachabilityFlagsReachable) ! = 0); BOOL needsConnection = ((flags & kSCNetworkReachabilityFlagsConnectionRequired) ! = 0); BOOL canConnectionAutomatically = (((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) ! = 0) || ((flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) ! = 0)); BOOL canConnectWithoutUserInteraction = (canConnectionAutomatically && (flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0); BOOL isNetworkReachable = (isReachable && (! needsConnection || canConnectWithoutUserInteraction)); AFNetworkReachabilityStatus status = AFNetworkReachabilityStatusUnknown;if (isNetworkReachable == NO) {
        status = AFNetworkReachabilityStatusNotReachable;
    }
#if	TARGET_OS_IPHONE
    else if((flags & kSCNetworkReachabilityFlagsIsWWAN) ! = 0) { status = AFNetworkReachabilityStatusReachableViaWWAN; }#endif
    else {
        status = AFNetworkReachabilityStatusReachableViaWiFi;
    }

    return status;
}
Copy the code

2. The status bar

  1. The height of the status bar has been changed from 20 to 44.
  2. In the process of modifying our macro encountered another pit, hereby remind:
/ / the original#define MPStatusBarHeight (20)/ / new#define MPStatusBarHeight (UIApplication.sharedApplication.statusBarFrame.size.height)// / Application statusBarFrame hides the status bar with cgRectZer@property (nonatomic,readonly) CGRect statusBarFrame __TVOS_PROHIBITED; // returns CGRectZero if the status bar is hidden
Copy the code

3. Share with friends

IPhone X needs to update the SDK to the latest version 6.8.0. Unfortunately, cocoapods is not available in all of umeng’s latest products, which requires manual integration. During the integration process, we encountered a pit: because our project used POD to reference both UmU sharing and UmU statistics, we just wanted to upgrade umU sharing, so we directly jumped to the document part of the integration of Umu sharing and performed the following operation:

Add UMShareSDK to project 3. Modify file reference error 4. Clear DerivedDataCopy the code

Error:

Asked umENG customer service (immediately replied, very helpful), because there is no integration of common base library, looking back at the document, found that integration of umeng any library needs to join the Common base library. However, once added to the common Base library, there will be a conflict with the pod reference of the friendly alliance statistics, so we have to change the statistics library and share library to manual reference.

Four,UIToolBar

I added uiBarButtonItems to both sides of UIToolBar. Before iOS 11, they were placed on the side. In iOS 11, the two items were next to each other. Need to add UIBarButtonSystemItemFlexibleSpace type of item can be in the middle.

Five,ALAssetsLibrarySave the picture and flash back

Before iOS 11, you could save photos to albums directly using the following code:

#import <AssetsLibrary/AssetsLibrary.h>
// ALAssetsLibrary
[[[ALAssetsLibrary alloc] init] writeImageDataToSavedPhotosAlbum:imageData metadata:nil completionBlock:^(NSURL *assetURL, NSError *error) {
    [self saveResultWithResult:(error == nil)];
}];
Copy the code

In iOS 11 it crashes and saves the image in a new pose:

  • Solution 1: Add a prompt for writing permission to the album to the infoPlist file
parameter key Xcode name version instructions
NSPhotoLibraryAddUsageDescription “Privacy – Photo Library Additions Usage Description” Specifies The reason for your app to get write-only access to the user’s photo library.seeNSPhotoLibraryAddUsageDescription for details. iOS 11 and later This parameter must be added for iOS 11
NSPhotoLibraryUsageDescription Privacy-photo Library Usage Description Specifies The reason for your app to access the user’s photo library.seeNSPhotoLibraryUsageDescription for details. IOS 6.0 and later This parameter must be added after iOS 10

Add directly to infoPlist (xcode open as Source Code) :

< key > NSPhotoLibraryUsageDescription < / key > < string > this App need your approval to read the media database < / string > < key > NSPhotoLibraryAddUsageDescription < / key > < string > this App need your approval to write media database < / string >Copy the code
  • Solution 2: If the write permission prompt is not added as in Scenario 1,ALAssetsLibraryWrite directly crashes, whilePHPhotoLibrarySaving the image directly triggers an Alert to ask the user for permission to write to the album.
#import <Photos/Photos.h>// PHPhotoLibrary - (void)saveImageByPHPhotoLibrary:(UIImage *)image { [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{ [PHAssetCreationRequest creationRequestForAssetFromImage:image];  } completionHandler:^(BOOL success, NSError * _Nullable error) { dispatch_async(dispatch_get_main_queue(), ^{ [self saveResultWithResult:(success && error == nil)]; }); }]; }Copy the code

update

Because WKWebView is used in the application, WKWebView will bring up the option to save the image without processing, and selecting save image will also crash. Therefore, this scheme cannot handle all the entries, and scheme 1 is recommended.

  • Solution 3: It is more reasonable to request the album permission before writing pictures to the album, referring to the iOS album, Camera, and address book permission

Vi. Keyboard Key string (Password Auto Fill)

1, problem,

In iOS 11, you’ll notice that some of your original input fields invoke the system keyboard like this:

🔑 in the upper right corner of the keyboard is the new iOS 11 feature Password Auto Fill. If you set UITextField contentType to Username and Password in the code, this icon will appear.

usernameTextField.textContentType = UITextContentType.username
passwordTextField.textContentType = UITextContentType.password
Copy the code

In some cases, in XIB files, if you do not specify a specific type, the keyboard will also appear 🔑 :

You just need to set contentType to something else:

2, about thePassword Auto Fill

For the adaptation of Password Auto Fill, please refer to iOS 11 —- Password Auto Fill (PS: feeling mechanism is similar to UniversalLink).

Seven, the react – native

You can refer to the following code to adapt the status bar and the bottom security field:

import { Dimensions, Platform } from 'react-native'

const { width, height } = Dimensions.get('window')

export const isIphoneX = () => (
    Platform.OS === 'ios'&&! Platform.isPad && ! Platform.isTVOS && (height === 812 || width === 812) ) const getStatusBarHeight = () => {if (Platform.OS === 'android') {
    return0}if (isIphoneX()) {
    return44}return 20
}

// const
export const IPHONEX_BOTTOM_HEIGHT = 34
export const STATUSBAR_HEIGHT = getStatusBarHeight()
Copy the code