Upload
avitotech
View
387
Download
1
Embed Size (px)
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