Статьи

iOS SDK: обнаружение сетевых изменений с доступностью

Большинство мобильных приложений по той или иной причине получают доступ к Интернету. Это подразумевает, что эти приложения будут — или должны — вести себя по-разному, когда нет сетевого подключения. В этом кратком совете я покажу вам, как обнаруживать изменения сетевого интерфейса, используя класс Reachability Tony Million .


Несмотря на то, что Apple предоставляет образец кода для мониторинга изменений в доступности сети, класс Reachability от Apple несколько устарел и не поддерживает ARC (автоматический подсчет ссылок). Если вы используете AFNetworking , то вы можете рассмотреть AFHTTPClient , который также позволяет отслеживать изменения сетевого интерфейса.

Тем не менее, мое предпочтительное решение — замечательный класс Reachability, созданный и поддерживаемый Tony Million . Он поддерживает ARC и использует GCD (Grand Central Dispatch). Позвольте мне показать вам, как интегрировать класс Reachability Тони.


Создайте новый проект в Xcode, выбрав шаблон приложения Single View Application из списка шаблонов (рисунок 1). Назовите свое приложение Reachability , введите идентификатор компании, установите iPhone для семейства устройств и установите флажок Использовать автоматический подсчет ссылок . Остальные флажки могут быть оставлены непроверенными для этого проекта (рисунок 2). Сообщите Xcode, где вы хотите сохранить проект, и нажмите « Создать» .

Быстрый совет для iOS: обнаружение изменений сети с достижимостью - выбор шаблона проекта
Рисунок 1: Выбор шаблона проекта
Быстрый совет для iOS: обнаружение изменений сети с достижимостью - настройка проекта
Рисунок 2: Настройка проекта

Интеграция класса Reachability Тони Миллиона тривиальна. Посетите страницу проекта GitHub , загрузите последнюю версию и перетащите Reachability.h / .m в свой проект Xcode (рисунок 3). Если вы выберете этот путь, обязательно скопируйте файлы классов в ваш проект Xcode (рисунок 4). Вы также можете использовать CocoaPods для добавления Reachability в ваш проект.

Быстрый совет для iOS: обнаружение изменений сети с достижимостью - добавление класса достижимости в ваш проект
Рисунок 3: Добавление класса достижимости в ваш проект
Быстрый совет для iOS: обнаружение сетевых изменений с помощью Reachability - убедитесь, что скопировали файлы классов в свой проект
Рисунок 4: Убедитесь, что скопировали файлы классов в ваш проект

Класс Reachability зависит от структуры конфигурации системы для некоторых ее функций. Выбрав свой проект в Навигаторе проектов , выберите цель « Достижимость» в списке целей, откройте вкладку « Фазы сборки » и разверните блок « Связать двоичные файлы с библиотеками» . Нажмите кнопку «плюс» и найдите SystemConfiguration.framework (рисунок 5).

Быстрый совет для iOS: обнаружение изменений в сети с достижимостью - свяжите свой проект с платформой конфигурации системы
Рисунок 5: Свяжите ваш проект с платформой конфигурации системы

Класс Reachability предоставляет два способа мониторинга изменений доступности сети: блоки и уведомления. Позвольте мне показать вам, как это работает.

Для простоты мы добавим логику достижимости в делегат приложения. Начните с добавления оператора импорта для Reachability.h в MTAppDelegate.m, как показано ниже.

1
2
3
4
#import «MTAppDelegate.h»
 
#import «Reachability.h»
#import «MTViewController.h»

Сначала нам нужно создать экземпляр класса application:didFinishLaunchingWithOptions: в application:didFinishLaunchingWithOptions: ( MTAppDelegate.m ), как показано ниже. Затем мы устанавливаем reachableBlock и unreachableBlock в экземпляре Reachability . reachableBlock вызывается, когда доступность сети меняется с недоступной на достижимую. Обратное верно для unreachableBlock . Ключевым является отправка экземпляру startNotifier сообщения startNotifier чтобы он знал, что должен начать мониторинг изменений достижимости. Также важно знать, что вызов startNotifier заставляет экземпляр startNotifier сохранять себя, что означает, что вам не нужно хранить ссылку на объект Reachability . Тем не менее, я не фанат этого подхода и чуть позже покажу вам альтернативное решение.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
— (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Initialize Reachability
    Reachability *reachability = [Reachability reachabilityWithHostname:@»www.google.com»];
 
    reachability.reachableBlock = ^(Reachability *reachability) {
        NSLog(@»Network is reachable.»);
    };
 
    reachability.unreachableBlock = ^(Reachability *reachability) {
        NSLog(@»Network is unreachable.»);
    };
 
    // Start Monitoring
    [reachability startNotifier];
 
    // Initialize View Controller
    self.viewController = [[MTViewController alloc] initWithNibName:@»MTViewController» bundle:nil];
 
    // Initialize Window
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
 
    // Configure Window
    [self.window setRootViewController:self.viewController];
    [self.window makeKeyAndVisible];
 
    return YES;
}

Прежде чем мы рассмотрим уведомления, я должен подчеркнуть, что доступные и недоступные блоки вызываются в фоновом потоке. Помните об этом, когда вам нужно обновить пользовательский интерфейс вашего приложения при изменении сетевого интерфейса.

Преимущество использования уведомлений для изменений достижимости состоит в том, что любой объект в вашем приложении может зарегистрироваться как наблюдатель для этих уведомлений. В отличие от использования блоков, уведомления о достижимости размещаются и доставляются в основной поток. Как вы можете видеть ниже, в application:didFinishLaunchingWithOptions: мы создаем экземпляр класса application:didFinishLaunchingWithOptions: и сообщаем ему начать мониторинг изменений в сети.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
— (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Initialize Reachability
    Reachability *reachability = [Reachability reachabilityWithHostname:@»www.google.com»];
 
    // Start Monitoring
    [reachability startNotifier];
 
    // Initialize View Controller
    self.viewController = [[MTViewController alloc] initWithNibName:@»MTViewController» bundle:nil];
 
    // Initialize Window
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
 
    // Configure Window
    [self.window setRootViewController:self.viewController];
    [self.window makeKeyAndVisible];
 
    return YES;
}

Например, если контроллер представления должен быть информирован об изменениях в доступности сети, то нам нужно добавить его в качестве наблюдателя уведомлений, которые Reachability экземпляр Reachability . Откройте MTViewController.m , добавьте оператор импорта для Reachability.h и обновите initWithNibName:bundle: как показано ниже.

1
2
3
#import «MTViewController.h»
 
#import «Reachability.h»
01
02
03
04
05
06
07
08
09
10
— (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
 
    if (self) {
        // Add Observer
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reachabilityDidChange:) name:kReachabilityChangedNotification object:nil];
    }
 
    return self;
}

Каждый раз, когда изменяется сетевой интерфейс, reachabilityDidChange: и контроллер представления может ответить соответствующим образом. Свойство object уведомления — это экземпляр Reachability который разместил уведомление. Класс Reachability предоставляет ряд полезных методов экземпляра, таких как isReachable , isReachableViaWWAN и isReachableViaWiFi . Вы даже можете указать экземпляру Reachability , должен ли он считать WWAN недоступным, соответствующим образом установив свойство reachableOnWWAN .

1
2
3
4
5
6
7
8
9
— (void)reachabilityDidChange:(NSNotification *)notification {
    Reachability *reachability = (Reachability *)[notification object];
 
    if ([reachability isReachable]) {
        NSLog(@»Reachable»);
    } else {
        NSLog(@»Unreachable»);
    }
}

Для приложений, которым требуется сетевое соединение, я обычно использую альтернативный подход для управления достижимостью. Я создаю отдельный класс с именем ReachabilityManager, который принимает шаблон синглтона. Объект singleton управляет экземпляром Reachability и предоставляет ряд полезных методов класса. Позвольте мне провести вас через внутренности этого класса.

Как я уже упоминал, класс MTReachabilityManager принимает одноэлементный шаблон и предоставляет доступ к одноэлементному объекту через sharedManager класса sharedManager . Это полезно, если объекту нужен прямой доступ к экземпляру reachability которым управляет одноэлементный объект.

Посредством ряда методов класса объекты могут запрашивать у менеджера достижимости текущий сетевой интерфейс. Кроме того, объекты все еще могут добавлять себя в качестве наблюдателей для уведомлений kReachabilityChangedNotification как мы видели ранее.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
#import <Foundation/Foundation.h>
 
@class Reachability;
 
@interface MTReachabilityManager : NSObject
 
@property (strong, nonatomic) Reachability *reachability;
 
#pragma mark —
#pragma mark Shared Manager
+ (MTReachabilityManager *)sharedManager;
 
#pragma mark —
#pragma mark Class Methods
+ (BOOL)isReachable;
+ (BOOL)isUnreachable;
+ (BOOL)isReachableViaWWAN;
+ (BOOL)isReachableViaWiFi;
 
@end

Реализация MTReachabilityManager не слишком удивительна. Если вы не знакомы с одноэлементным шаблоном, то реализация sharedManager может показаться немного странной. Хотя класс MTReachabilityManager использует шаблон синглтона, технически возможно создать экземпляры класса. Мы могли бы предотвратить это, проверив значение _sharedManager в init , но я предполагаю, что тот, кто использует класс MTReachabilityManager , взглянул на файл интерфейса класса, обнаружив, что он принимает шаблон синглтона.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#import «MTReachabilityManager.h»
 
#import «Reachability.h»
 
@implementation MTReachabilityManager
 
#pragma mark —
#pragma mark Default Manager
+ (MTReachabilityManager *)sharedManager {
    static MTReachabilityManager *_sharedManager = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _sharedManager = [[self alloc] init];
    });
 
    return _sharedManager;
}
 
#pragma mark —
#pragma mark Memory Management
— (void)dealloc {
    // Stop Notifier
    if (_reachability) {
        [_reachability stopNotifier];
    }
}
 
#pragma mark —
#pragma mark Class Methods
+ (BOOL)isReachable {
    return [[[MTReachabilityManager sharedManager] reachability] isReachable];
}
 
+ (BOOL)isUnreachable {
    return ![[[MTReachabilityManager sharedManager] reachability] isReachable];
}
 
+ (BOOL)isReachableViaWWAN {
    return [[[MTReachabilityManager sharedManager] reachability] isReachableViaWWAN];
}
 
+ (BOOL)isReachableViaWiFi {
    return [[[MTReachabilityManager sharedManager] reachability] isReachableViaWiFi];
}
 
#pragma mark —
#pragma mark Private Initialization
— (id)init {
    self = [super init];
 
    if (self) {
        // Initialize Reachability
        self.reachability = [Reachability reachabilityWithHostname:@»www.google.com»];
 
        // Start Monitoring
        [self.reachability startNotifier];
    }
 
    return self;
}
 
@end

Если вы решите принять этот альтернативный подход и использовать диспетчер достижимости, который управляет экземпляром класса Reachability , не забудьте создать экземпляр объекта singleton при запуске приложения. Вы можете сделать это, вызвав sharedManager MTReachabilityManager класса MTReachabilityManager .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
— (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Instantiate Shared Manager
    [MTReachabilityManager sharedManager];
 
    // Initialize View Controller
    self.viewController = [[MTViewController alloc] initWithNibName:@»MTViewController» bundle:nil];
 
    // Initialize Window
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
 
    // Configure Window
    [self.window setRootViewController:self.viewController];
    [self.window makeKeyAndVisible];
 
    return YES;
}

Уведомление пользователя или обновление пользовательского интерфейса приложения при изменении сетевого интерфейса не только приводит к улучшению взаимодействия с пользователем, Apple требует, чтобы вы делали это, если ваше приложение использует сетевое подключение. Это требует определенных усилий, но класс Reachability делает это намного проще.