Статьи

iOS 6 и социальная платформа: запросы Twitter

Из этого туториала вы узнаете, как использовать iOS 6 SDK и Social Framework для загрузки динамического контента из Twitter. Для этого я научу вас, как создать приложение для создания профиля в Twitter. Читай дальше!


Откройте Xcode и выберите «Создать новый проект Xcode». Выберите «Очистить приложение» и нажмите «Далее». Введите имя для своего проекта (я назвал мой «Профиль Twitter»), убедитесь, что вы выбрали iPhone для устройства, а затем установите все флажки, кроме флажка Use Core Data. После этого нажмите «Далее» и выберите место для сохранения вашего проекта, прежде чем нажать «Создать».

Создать проект

Мы хотим использовать это приложение только в портретном режиме, поэтому перейдите в раздел «Поддерживаемые ориентации интерфейса» и отмените выбор ориентации ландшафта.

«Поддерживаемые

Нам потребуется добавить три Frameworks в наш проект: Social Framework для выполнения запроса, Accounts Framework для использования учетной записи Twitter пользователя и QuartzCore Framework, чтобы немного настроить наш интерфейс.

Перейдите на вкладку «Этапы сборки» и используйте параметр «Связать двоичные файлы с библиотеками». Нажмите кнопку «+», чтобы добавить новую платформу. Введите «Social» в поле поиска и выберите опцию Social.framework, которая появится в списке. Нажмите «Добавить», чтобы включить этот фреймворк в фазу связывания вашего проекта. Сделайте то же самое для платформ Accounts и QuartzCore, введя «Accounts» и «QuartzCore» в поле поиска.

«рамочные»

Перейдите в «Файл»> «Новый»> «Файл …» или нажмите ⌘N, чтобы создать новый файл. Перейдите в раздел «Использование интерфейса», выберите «Раскадровка» и нажмите «Далее». Убедитесь, что для семейства устройств установлено значение «iPhone», и снова нажмите «Далее». Назовите раскадровку MainStoryboard и нажмите «Создать».

"Создайте

Теперь мы должны связать раскадровку с нашим проектом. Выберите название проекта в меню навигатора XCode и выберите текущую цель (в нашем случае «Профиль Twitter»). Затем выберите вкладку «Summery» и перейдите в раздел «Информация о развертывании iPhone / iPad». Оказавшись там, выберите нашу раскадровку под названием «MainStoryboard» для главной раскадровки.

«MainStoryboard»

Последнее, что нам нужно сделать, чтобы наша раскадровка работала, — это изменить application: didFinishLaunchWithOptions: метод, поэтому откройте AppDelegate.m и измените метод следующим образом:

1
2
3
4
— (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    return YES;
}

Откройте раскадровку и перетащите контроллер навигации из библиотеки объектов на холст. Выберите контроллер табличного представления, подключенный к контроллеру навигации, и удалите его. Теперь перетащите View Controller из библиотеки объектов на холст. Удерживая клавишу CTRL, перетащите курсор с контроллера навигации на контроллер просмотра и выберите «корневой контроллер просмотра» во всплывающем меню. Выберите контроллер навигации, откройте инспектор файлов, а затем отмените выбор «Использовать автоматическое расположение», поскольку мы не будем использовать эту новую функцию для нашего приложения. Наконец, дважды щелкните на панели навигации только что созданного View Controller и введите «Имя пользователя» в качестве заголовка.

Теперь выберите текстовое поле из библиотеки объектов и добавьте его в View Controller. Выберите текстовое поле и откройте инспектор атрибутов. Введите «Имя пользователя» в качестве заполнителя и убедитесь, что выбрана опция «Очистить, когда редактирование начинается». Затем возьмите кнопку из библиотеки объектов, добавьте ее в View Controller и измените заголовок на «Показать информацию».

Наконец, убедитесь, что текстовое поле и кнопка расположены следующим образом:

«Имя пользователя

Нам также нужен экран для отображения профиля Twitter, поэтому перетащите новый View Controller из библиотеки объектов на холст. Удерживая клавишу CTRL, перетащите кнопку «Показать информацию» на View Controller и выберите «нажать» во всплывающем меню. Затем дважды щелкните на панели навигации второго View Controller и введите «Профиль» в качестве заголовка.

Нам понадобится много ярлыков и несколько изображений на этом экране для отображения информации профиля. Сначала добавьте представление изображения в контроллер представления профиля и обязательно выровняйте его по верху. Затем откройте инспектор размера и установите размер 320 х 160 пикселей. Также измените автоматическое изменение размера следующим образом:

"Баннер

Добавьте еще один вид изображения поверх предыдущего. Перейдите в инспектор размера и измените размер, координаты и авторазмер, как показано ниже:

"Профиль

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

"Имя

Затем откройте инспектор атрибутов и введите «Имя» для текста метки. Измените цвет на белый, сделайте шрифт полужирным и установите выравнивание по центру. Наконец мы добавим тень на этот ярлык. Установите вертикальное смещение тени на 1, чтобы тень появлялась под текстом. Нажмите на цвет тени и сделайте цвет черным с непрозрачностью 75%.

"Тень

Эта метка была для имени, но нам также нужна метка для имени пользователя, поэтому выберите метку, которую мы только что создали, и нажмите ⌘C ⌘V, чтобы скопировать и вставить ее. Измените текст на «@username» и измените координаты X и Y на 20 и 120. Мы также хотим сделать этот шрифт немного меньше, поэтому откройте инспектор атрибутов и измените размер шрифта на 14.

Нам также нужно еще шесть ярлыков, чтобы показать количество твитов, подписчиков и подписчиков. К счастью для нас, нам нужно только добавить два, и мы можем скопировать и вставить остальные четыре. Добавьте новую метку в View Controller, сделайте его шириной 74 пикселя, измените координаты X и Y на 20 и 168. Введите «0» в качестве текста для этой метки. Затем добавьте новую метку, также сделайте ее шириной 74 пикселя, но на этот раз измените координаты X и Y на 20 и 190. Откройте инспектор атрибутов и присвойте метке светло-серый цвет. Также измените текст на «Tweets».

Выберите обе надписи, которые мы только что создали, и ALT перетащите их в центр. Таким образом, мы создаем копию двух меток. ALT перетащите еще раз, но на этот раз выровняйте метки вправо. Теперь мы создали эти шесть лейблов довольно быстро. Измените текст центральной метки на «Following», а текст правой метки на «Followers».

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

«TextView

С этими параметрами наше приложение будет хорошо смотреться как на iPhone 5, так и на старом iPhone 4. Вы можете просмотреть раскадровку в 3,5-дюймовом экране, нажав эту кнопку в правом нижнем углу:

«Кнопка»

Теперь откройте инспектор атрибутов и удалите текст текстового представления. Также обязательно отмените выбор параметра «Редактируемый».

Теперь интерфейс должен выглядеть следующим образом:

"Законченный

Теперь, когда мы завершили наш интерфейс, я думаю, что сейчас самое время протестировать наше приложение. Нажмите Build and Run или нажмите ⌘R, чтобы протестировать приложение. Приложение должно отображать простой навигационный контроллер с текстовым полем и кнопкой. Если вы нажмете кнопку, вы увидите страницу профиля, которую мы только что создали. Имя и имя пользователя не легко прочитать, но мы позаботимся об этом позже.


Перейдите в «Файл»> «Создать»> «Файл …», чтобы создать новый файл. Выберите «Objective-C class» и нажмите «Next». Введите «UsernameViewController» для класса и убедитесь, что это подкласс UIViewController и что оба флажка не установлены. Нажмите «Далее» еще раз, а затем нажмите «Создать».

Откройте UsernameViewController.h и измените код следующим образом:

1
2
3
4
5
6
7
8
#import <UIKit/UIKit.h>
 
@interface UsernameViewController : UIViewController
{
    IBOutlet UITextField *usernameTextfield;
}
 
@end

Здесь мы просто создаем простой выход для нашего текстового поля, которое мы будем использовать для передачи введенного имени пользователя на страницу профиля.

Затем снова откройте раскадровку и выберите имя пользователя View Controler. Откройте Identity Inspector и измените класс на UsernameViewController, который мы только что создали. После этого откройте инспектор соединений и подключите выходное поле usernameTextfield с текстовым полем.

Теперь откройте UsernameViewController.m и добавьте следующую строку в #import "UsernameViewController.h" :

1
#import «ProfileViewController.h»

Здесь мы уже импортируем ProfileViewController, который мы создадим позже в этом уроке. Затем добавьте следующий метод в метод didReceiveMemoryWarning :

1
2
3
4
5
— (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    ProfileViewController *profileViewController = [segue destinationViewController];
    [profileViewController setUsername:usernameTextfield.text];
}

Здесь мы передаем имя пользователя в ProfileViewController, который мы создадим через минуту.


Чтобы создать эти розетки, сначала нужно создать несколько новых файлов, поэтому перейдите в «Файл»> «Создать»> «Файл …». Выберите «Objective-C class» и нажмите «Next». Введите «ProfileViewController» для класса и убедитесь, что это подкласс UIViewController и что оба флажка не установлены. Нажмите «Далее» еще раз, а затем нажмите «Создать».

Откройте ProfileViewController.h и измените код следующим образом:

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
#import <UIKit/UIKit.h>
#import <Accounts/Accounts.h>
#import <Social/Social.h>
#import <QuartzCore/QuartzCore.h>
 
@interface ProfileViewController : UIViewController
{
    IBOutlet UIImageView *profileImageView;
    IBOutlet UIImageView *bannerImageView;
     
    IBOutlet UILabel *nameLabel;
    IBOutlet UILabel *usernameLabel;
     
    IBOutlet UILabel *tweetsLabel;
    IBOutlet UILabel *followingLabel;
    IBOutlet UILabel *followersLabel;
     
    IBOutlet UITextView *lastTweetTextView;
     
    NSString *username;
}
 
@property (nonatomic, retain) NSString *username;
 
@end

Здесь мы сначала импортируем фреймворки, которые мы добавили ранее в наш проект. После этого мы создаем несколько выходов для элементов, которые будут отображать изображение профиля, и, наконец, мы создаем строку, которая будет содержать введенное имя пользователя. Мы устанавливаем эту строку в prepareForSegue:sender: метод, который мы создали на предыдущем шаге.

Откройте раскадровку и выберите профиль View Controller. Откройте Identity Inspector и измените класс на ProfileViewController. После этого откройте инспектор соединений и подключите розетки с соответствующими элементами интерфейса. Просто убедитесь, что вы соединяете розетки tweetsLabel, followLabel и followLabel с метками над метками с соответствующим текстом. Поэтому не соединяйте розетку tweetsLabel с надписью «Tweets», а с надписью над ней.

Наконец, откройте ProfileViewController.m и добавьте следующую строку под @implementation:

1
@synthesize username;

Файл ProfileViewController.m по-прежнему должен быть открыт, поэтому перейдите к методу viewDidLoad и измените его следующим образом:

01
02
03
04
05
06
07
08
09
10
11
12
— (void)viewDidLoad
{
    [super viewDidLoad];
     
    [profileImageView.layer setBorderWidth:4.0f];
    [profileImageView.layer setBorderColor:[[UIColor whiteColor] CGColor]];
     
    [profileImageView.layer setShadowRadius:3.0];
    [profileImageView.layer setShadowOpacity:0.5];
    [profileImageView.layer setShadowOffset:CGSizeMake(1.0, 0.0)];
    [profileImageView.layer setShadowColor:[[UIColor blackColor] CGColor]];
}

Здесь мы используем QuartzCore Framework, чтобы придать profileImageView границу и некоторую тень.


Добавьте следующий метод в метод didReceiveMemoryWarning :

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
— (void) getInfo
{
    // Request access to the Twitter accounts
     
    ACAccountStore *accountStore = [[ACAccountStore alloc] init];
    ACAccountType *accountType = [accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];
     
    [accountStore requestAccessToAccountsWithType:accountType options:nil completion:^(BOOL granted, NSError *error){
        if (granted) {
             
            NSArray *accounts = [accountStore accountsWithAccountType:accountType];
             
            // Check if the users has setup at least one Twitter account
             
            if (accounts.count > 0)
            {
                ACAccount *twitterAccount = [accounts objectAtIndex:0];
                 
                // Creating a request to get the info about a user on Twitter
                 
                SLRequest *twitterInfoRequest = [SLRequest requestForServiceType:SLServiceTypeTwitter requestMethod:SLRequestMethodGET URL:[NSURL URLWithString:@»https://api.twitter.com/1.1/users/show.json»] parameters:[NSDictionary dictionaryWithObject:username forKey:@»screen_name»]];
                [twitterInfoRequest setAccount:twitterAccount];
                 
                // Making the request
                 
                [twitterInfoRequest performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) {
                    dispatch_async(dispatch_get_main_queue(), ^{
                         
                        // Check if we reached the reate limit
                         
                        if ([urlResponse statusCode] == 429) {
                            NSLog(@»Rate limit reached»);
                            return;
                        }
                         
                        // Check if there was an error
                         
                        if (error) {
                            NSLog(@»Error: %@», error.localizedDescription);
                            return;
                        }
                         
                        // Check if there is some response data
                         
                        if (responseData) {
                             
                            NSError *error = nil;
                            NSArray *TWData = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingMutableLeaves error:&error];
                             
                             
                            // Filter the preferred data
                             
                            NSString *screen_name = [(NSDictionary *)TWData objectForKey:@»screen_name»];
                            NSString *name = [(NSDictionary *)TWData objectForKey:@»name»];
                             
                            int followers = [[(NSDictionary *)TWData objectForKey:@»followers_count»] integerValue];
                            int following = [[(NSDictionary *)TWData objectForKey:@»friends_count»] integerValue];
                            int tweets = [[(NSDictionary *)TWData objectForKey:@»statuses_count»] integerValue];
                             
                            NSString *profileImageStringURL = [(NSDictionary *)TWData objectForKey:@»profile_image_url_https»];
                            NSString *bannerImageStringURL =[(NSDictionary *)TWData objectForKey:@»profile_banner_url»];
                             
                             
                            // Update the interface with the loaded data
                             
                            nameLabel.text = name;
                            usernameLabel.text= [NSString stringWithFormat:@»@%@»,screen_name];
                             
                            tweetsLabel.text = [NSString stringWithFormat:@»%i», tweets];
                            followingLabel.text= [NSString stringWithFormat:@»%i», following];
                            followersLabel.text = [NSString stringWithFormat:@»%i», followers];
                             
                            NSString *lastTweet = [[(NSDictionary *)TWData objectForKey:@»status»] objectForKey:@»text»];
                            lastTweetTextView.text= lastTweet;
                             
                             
                             
                            // Get the profile image in the original resolution
                             
                            profileImageStringURL = [profileImageStringURL stringByReplacingOccurrencesOfString:@»_normal» withString:@»»];
                            [self getProfileImageForURLString:profileImageStringURL];
                             
                             
                            // Get the banner image, if the user has one
                             
                            if (bannerImageStringURL) {
                                NSString *bannerURLString = [NSString stringWithFormat:@»%@/mobile_retina», bannerImageStringURL];
                                [self getBannerImageForURLString:bannerURLString];
                            } else {
                                bannerImageView.backgroundColor = [UIColor underPageBackgroundColor];
                            }
                        }
                    });
                }];
            }
        } else {
            NSLog(@»No access granted»);
        }
    }];
}

Это много кода, но я объясню это шаг за шагом.

1
2
ACAccountStore *accountStore = [[ACAccountStore alloc] init];
ACAccountType *accountType = [accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];

Здесь мы сначала инициализируем объект ACAccountStore, который позволит нам получить доступ к учетным записям пользователей. После этого мы создаем экземпляр ACAccountType, вызываем метод accountTypeWithAccountTypeIdentifier для только что созданного экземпляра ACAccountStore, а затем устанавливаем тип учетной записи Twitter. Вы можете использовать тот же метод, если хотите использовать Facebook, но тогда вам нужно будет установить идентификатор типа учетной записи ACAccountTypeIdentifierFacebook .

1
2
3
4
[accountStore requestAccessToAccountsWithType:accountType options:nil completion:^(BOOL granted, NSError *error){
        if (granted) {
    }
}];

Здесь мы просто просим пользователя предоставить нашему приложению доступ к его учетным записям.

1
2
3
4
5
6
NSArray *accounts = [accountStore accountsWithAccountType:accountType];
             
if (accounts.count > 0)
{
    ACAccount *twitterAccount = [accounts objectAtIndex:0];
}

Здесь мы создаем массив всех учетных записей Twitter пользователя. Мы проверяем, есть ли у пользователя учетные записи Twitter. Если это так, мы создаем экземпляр ACAccount первой учетной записи Twitter в этом массиве. Для простоты мы используем первую учетную запись в этом руководстве, но в реальном приложении вы должны предоставить пользователю возможность выбрать предпочитаемую учетную запись Twitter, если их больше 1.

1
2
SLRequest *twitterInfoRequest = [SLRequest requestForServiceType:SLServiceTypeTwitter requestMethod:SLRequestMethodGET URL:[NSURL URLWithString:@»https://api.twitter.com/1.1/users/show.json»] parameters:[NSDictionary dictionaryWithObject:username forKey:@»screen_name»]];
             [twitterInfoRequest setAccount:twitterAccount];

Здесь мы создаем наш запрос, который будет вызывать API Twitter. Мы устанавливаем тип сервиса в Twitter и метод запроса в GET. Мы не хотим получать информацию о пользователе в Твиттере. Вы также можете использовать методы запроса POST и DELETE. С помощью POST вы можете обновить изображение профиля или опубликовать твит. С помощью DELETE вы можете удалять вещи из своего аккаунта. URL-адрес в этом руководстве будет следующим: https://api.twitter.com/1.1/users/show.json . Этот URL будет гарантировать, что запрос возвращает различную информацию об указанном пользователе в формате JSON. В качестве параметра мы добавляем введенное имя пользователя для ключа screen_name, чтобы получить информацию об этом пользователе. После этого мы устанавливаем учетную запись для запроса к экземпляру ACAccount.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
[twitterInfoRequest performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) {
                    dispatch_async(dispatch_get_main_queue(), ^{
                         
                         
                        if ([urlResponse statusCode] == 429) {
                            NSLog(@»Rate limit reached»);
                            return;
                        }
                         
                         
                        if (error) {
                            NSLog(@»Error: %@», error.localizedDescription);
                            return;
                        }
         });
                }];

Здесь мы фактически делаем запрос и проверяем, что он загружается асинхронно, чтобы наш интерфейс продолжал отвечать на запросы во время загрузки. Мы делаем это с GCD, Grand Central Dispatch. Я не буду вдаваться в подробности, но вы можете найти больше информации об этом здесь . Когда запрос завершен, мы сначала проверяем, не достигло ли наше приложение ограничения скорости. После этого мы проверяем, не было ли ошибки.

1
2
3
4
5
if (responseData) {
                             
                            NSError *error = nil;
                            NSArray *TWData = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingMutableLeaves error:&error];
}

Здесь мы проверяем, вернул ли запрос некоторые данные ответа. Если это так, мы создаем массив из возвращенного файла JSON.

1
2
3
4
5
6
7
8
9
NSString *screen_name = [(NSDictionary *)TWData objectForKey:@»screen_name»];
                   NSString *name = [(NSDictionary *)TWData objectForKey:@»name»];
                    
                   int followers = [[(NSDictionary *)TWData objectForKey:@»followers_count»] integerValue];
                   int following = [[(NSDictionary *)TWData objectForKey:@»friends_count»] integerValue];
                   int tweets = [[(NSDictionary *)TWData objectForKey:@»statuses_count»] integerValue];
                    
                   NSString *profileImageStringURL = [(NSDictionary *)TWData objectForKey:@»profile_image_url_https»];
                   NSString *bannerImageStringURL =[(NSDictionary *)TWData objectForKey:@»profile_banner_url»];

Здесь мы фильтруем предпочтительные данные, мы получаем имя пользователя, имя_экрана (имя пользователя), количество твитов, подписчиков и подписчиков. Мы также получаем URL-адреса для изображения профиля и баннера.

1
2
3
4
5
6
7
8
9
nameLabel.text = name;
                    usernameLabel.text= [NSString stringWithFormat:@»@%@»,screen_name];
                     
                    tweetsLabel.text = [NSString stringWithFormat:@»%i», tweets];
                    followingLabel.text= [NSString stringWithFormat:@»%i», following];
                    followersLabel.text = [NSString stringWithFormat:@»%i», followers];
                     
                    NSString *lastTweet = [[(NSDictionary *)TWData objectForKey:@»status»] objectForKey:@»text»];
                    lastTweetTextView.text= lastTweet;

Здесь мы просто обновляем текстовые свойства наших меток и текстового представления только что полученными и отфильтрованными данными.

1
2
profileImageStringURL = [profileImageStringURL stringByReplacingOccurrencesOfString:@»_normal» withString:@»»];
[self getProfileImageForURLString:profileImageStringURL];

Поскольку Twitter использует URL-адрес для изображения профиля нормального размера, который составляет всего 48 на 48 пикселей, мы удаляем строку «_normal», чтобы мы могли получить исходное изображение профиля. После этого мы вызываем метод getProfileImageForURLString: для загрузки изображения профиля. Мы создадим этот метод через несколько минут.

1
2
3
4
5
6
if (bannerImageStringURL) {
                                NSString *bannerURLString = [NSString stringWithFormat:@»%@/mobile_retina», bannerImageStringURL];
                                [self getBannerImageForURLString:bannerURLString];
                            } else {
                                bannerImageView.backgroundColor = [UIColor underPageBackgroundColor];
                            }

Здесь мы проверяем, есть ли у пользователя баннер профиля. Если это так, мы обновляем URL-адрес, чтобы получить мобильную версию баннера с сетчаткой размером 640×320 пикселей. После этого мы вызываем метод getBannerImageForURLString: для загрузки баннера. Если у пользователя нет баннера профиля, мы даем bannerImageView цвет фона.

Теперь добавьте следующие методы в метод getInfo для загрузки профиля и изображения баннера:

01
02
03
04
05
06
07
08
09
10
11
12
13
— (void) getProfileImageForURLString:(NSString *)urlString;
{
    NSURL *url = [NSURL URLWithString:urlString];
    NSData *data = [NSData dataWithContentsOfURL:url];
    profileImageView.image = [UIImage imageWithData:data];
}
 
— (void) getBannerImageForURLString:(NSString *)urlString;
{
    NSURL *url = [NSURL URLWithString:urlString];
    NSData *data = [NSData dataWithContentsOfURL:url];
    bannerImageView.image = [UIImage imageWithData:data];
}

Последнее, что нам нужно сделать, чтобы завершить наше приложение, — это вызвать метод getInfo методе viewDidLoad , поэтому перейдите к методу viewDidLoad и добавьте следующую строку в нижней части этого метода:

1
[self getInfo];

Теперь, когда мы закончили наше приложение, нажмите Build and Run или нажмите pressR, чтобы протестировать приложение. Если вы вводите имя пользователя от кого-то в Twitter, вы должны увидеть мини-профиль с информацией об этом пользователе.

Финальное приложение

Спасибо за чтение этого учебника о создании запроса в Twitter с новой социальной структурой. Если вы хотите узнать больше об API Twitter, я предлагаю вам взглянуть на официальную документацию . Надеюсь, вам понравился этот урок, и если у вас есть вопросы или комментарии по этому уроку, оставьте их в разделе комментариев ниже!