"Подходы, используемые в разработке iOS-клиента...

  • View
    387

  • Download
    1

  • Category

    Mobile

Preview:

Citation preview

Подходы, используемые в разработке iOS-

клиента ViberКирилл Лашкевич

Кратко о Viber iOS• 6 лет разработки

• ~1M SLOC

• Команда iOS: 20 человек в 4 странах и 5 городах

• 6 языков программирования

Археология программирования

6 языков

6 языков• ASM

• C

• C++

6 языков• ASM

• C

• C++

• ObjC

• ObjC++

• Swift

Используем фреймворки и инструменты на пределе

возможностей• CoreData

• Xcode

• clang

• Git

• Hardware

🎤

🎤 Encode

🎤 Encode Packetize

🎤 Encode Packetize Send

🎤 Encode Packetize Send

🎤 Encode Packetize Send

NAT�Traversal

🎤 Encode Packetize Send

Receive

NAT�Traversal

🎤 Encode Packetize Send

ReceiveDepacketize

NAT�Traversal

🎤 Encode Packetize Send

ReceiveDepacketizeDecode

NAT�Traversal

🔊

🎤 Encode Packetize Send

ReceiveDepacketizeDecode

NAT�Traversal

🔊

📺

🎥🎤 Encode Packetize Send

ReceiveDepacketizeDecode

Encode Packetize Send

ReceiveDepacketizeDecode

NAT�Traversal

🔊

📺

🎥🎤 Encode Packetize Send

ReceiveDepacketizeDecode

Encode Packetize Send

ReceiveDepacketizeDecode

NAT�Traversal

sync

🔊

📺

🎥🎤 Encode Packetize Send

ReceiveDepacketizeDecode

Encode Packetize Send

ReceiveDepacketizeDecode

NAT�Traversal

sync sync

🔊

📺

🎥🎤 Encode Packetize Send

ReceiveDepacketizeDecode

Encode Packetize Send

ReceiveDepacketizeDecode

NAT�Traversal

sync sync

sync

🔊

📺

🎥🎤 Encode Packetize Send

ReceiveDepacketizeDecode

Encode Packetize Send

ReceiveDepacketizeDecode

NAT�Traversal

sync sync

sync

Capability�Negotiation

🔊

📺

🎥🎤 Encode Packetize Send

ReceiveDepacketizeDecode

Encode Packetize Send

ReceiveDepacketizeDecode

NAT�Traversal

sync sync

sync

Capability�NegotiationAEC

🔊

📺

🎥🎤 Encode Packetize Send

ReceiveDepacketizeDecode

Encode Packetize Send

ReceiveDepacketizeDecode

NAT�Traversal

sync sync

sync

Capability�NegotiationAEC

BitrateControl

🔊

📺

🎥🎤 Encode Packetize Send

ReceiveDepacketizeDecode

Encode Packetize Send

ReceiveDepacketizeDecode

NAT�Traversal

sync sync

sync

Capability�NegotiationAEC

BitrateControl

FEC

Git

• ~120 комиков в неделю

• 32k всего

• 10k мержей

• неизвестное количество веток

• 15 прилинкованных внешних origins

Управление внешними зависимостями

• CocoaPods, Carthage • git submodules • git subtrees

Управление внешними зависимостями

• CocoaPods, Carthage • git submodules • git subtrees

LibViber

Core

Media�Engine

Codec Codec

Viber�iOS

DSP

RAC Mantle

LibViber

Core

Media�Engine

Codec Codec

Viber�iOS

DSP

RAC Mantle

LibViber

Core

Media�Engine

Codec Codec

Viber�iOS

DSP

RAC Mantle

LibViber

Core

Media�Engine

Codec Codec

Viber�iOS

DSP

RAC Mantle

LibViber

Core

Media�Engine

Codec Codec

Viber�iOS

DSP

RAC Mantle

LibViber

Core

Media�Engine

Codec Codec

Viber�iOS

DSP

RAC Mantle

LibViber

Core

Media�Engine

Codec Codec

Viber�iOS

DSP

RAC Mantle

LibViber

Core

Media�Engine

Codec Codec

Viber�iOS

DSP

RAC Mantle

LibViber

Core

Media�Engine

Codec Codec

Viber�iOS

DSP

RAC Mantle

Git submodulesgit pull … && git submodule update --recursive

git status, --git-dir, --work-tree, git archive игнорируют сабмодули

git worktree игнорируют сабмодули

Разграничение доступа к репозиториям

Кроссплатформенный подход

LibViber

Core

Media�Engine

Codec Codec

Viber�iOS

DSP

RAC Mantle

LibViber

Core

Media�Engine

Codec Codec

Viber�iOS

DSP

RAC Mantle

Сборка

Сборка

Сборка

• cmake, scons, GYP, qmake

Сборка

• cmake, scons, GYP, qmake

• Xcode, xcodebuild

Сборка

• cmake, scons, GYP, qmake

• Xcode, xcodebuild

• Workspace, project, target

Сборка

• cmake, scons, GYP, qmake

• Xcode, xcodebuild

• Workspace, project, target

• External build, Run Script

1 Project 1 Target

1 Project N Targets

1 Project N Subprojects

1 Workspace N Projects

+ external build

+ external build

Проблемы Xcode

• Не все возможности документированы

• Сборка специфических файлов под разные архитектуры (armv7/arm64)

• Скорость сборки

Swift

Swift• Мы используем Swift!

Swift• Мы используем Swift!

• 15-строчный скрипт для генерации иконки с версией сборки

CoreData

CoreDataПоучительная история

CoreDataПоучительная история

Many-To-Many

CoreDataПоучительная история

Many-To-Many

+Core data migration

ReactiveCocoa✓Замена KVO

✓Элементы функционального программирования в ObjC

✓Меньше изменяемого состояния -> меньше багов

- Крутая кривая обучения

- Слишком много блоков в коде

–Alex A, iOS team lead

“Зачем мы засунули RAC и не можем высунуть?”

RAC(self, label.text) = RACObserve(self, name);

RAC(self, label.text) = RACObserve(self, name);

http://www.raywenderlich.com/62796/reactivecocoa-tutorial-pt1

[[[[[[[self requestAccessToTwitterSignal] then:^RACSignal *{ @strongify(self) return self.searchText.rac_textSignal; }] filter:^BOOL(NSString *text) { @strongify(self) return [self isValidSearchText:text]; }] throttle:0.5] flattenMap:^RACStream *(NSString *text) { @strongify(self) return [self signalForSearchWithText:text]; }] deliverOn:[RACScheduler mainThreadScheduler]] subscribeNext:^(NSDictionary *jsonSearchResult) { NSArray *tweets = [jsonSearchResult[@"statuses"] .rac_sequence map:^(id tweet) { return [RWTweet tweetWithStatus:tweet]; }].array; [self.resultsViewController displayTweets:tweets]; } error:^(NSError *error) { NSLog(@"An error occurred: %@", error); }];

[[[[[[[self requestAccessToTwitterSignal] then:^RACSignal *{ @strongify(self) return self.searchText.rac_textSignal; }] filter:^BOOL(NSString *text) { @strongify(self) return [self isValidSearchText:text]; }] throttle:0.5] flattenMap:^RACStream *(NSString *text) { @strongify(self) return [self signalForSearchWithText:text]; }] deliverOn:[RACScheduler mainThreadScheduler]] subscribeNext:^(NSDictionary *jsonSearchResult) { NSArray *tweets = [jsonSearchResult[@"statuses"] .rac_sequence map:^(id tweet) { return [RWTweet tweetWithStatus:tweet]; }].array; [self.resultsViewController displayTweets:tweets]; } error:^(NSError *error) { NSLog(@"An error occurred: %@", error); }];

Проблемы с self в ObjC

• self захватывается по сильной ссылке

• Доступ к _ivar происходит через неявный self ^ { NSLog(@"%@", _ivar); }; ^ { NSLog(@"%@", self->_ivar); };

• Как результат циклическая ссылка если блок сохранился как в поле объекта

@weakself

https://habrahabr.ru/company/viber/blog/232185/

@weakself• Безопасное использование self в блоках: слабая ссылка пока блок не вызван и сильная во время вызова

• self называется self

• Проверка в рантайме на доступ к _ivar в блоках через неявный self

https://habrahabr.ru/company/viber/blog/232185/

[RACObserve(self, pttState) doNext: @weakselfnotnil(^(NSNumber *state)) { self.isRecording = !!state.intValue; } @weakselfend];

[RACObserve(self, pttState) doNext: @weakselfnotnil(^(NSNumber *state)) { self.isRecording = !!state.intValue; } @weakselfend];

[RACObserve(self, pttState) doNext: @weakselfnotnil(^(NSNumber *state)) { self.isRecording = !!state.intValue; } @weakselfend];

1628 блоков в проекте используют weakself

CrashlyticsПросто используйте её, она клевая

@notorca