{"id":20078100,"url":"https://github.com/quickblox/q-municate-services-ios","last_synced_at":"2025-05-05T22:32:00.388Z","repository":{"id":30376057,"uuid":"33928671","full_name":"QuickBlox/q-municate-services-ios","owner":"QuickBlox","description":"Easy-to-use services for Quickblox SDK, for speeding up development of iOS chat applications","archived":false,"fork":false,"pushed_at":"2021-08-18T10:03:01.000Z","size":18861,"stargazers_count":31,"open_issues_count":2,"forks_count":42,"subscribers_count":18,"default_branch":"master","last_synced_at":"2024-10-18T16:18:23.243Z","etag":null,"topics":["auth","cache","chat","contacts","dialog","easy","groupchat","ios","objective-c","pushnotificaitions","quickblox","services","users"],"latest_commit_sha":null,"homepage":"","language":"Objective-C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/QuickBlox.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-04-14T11:49:44.000Z","updated_at":"2021-08-18T10:03:04.000Z","dependencies_parsed_at":"2022-09-22T00:22:57.741Z","dependency_job_id":null,"html_url":"https://github.com/QuickBlox/q-municate-services-ios","commit_stats":null,"previous_names":[],"tags_count":33,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/QuickBlox%2Fq-municate-services-ios","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/QuickBlox%2Fq-municate-services-ios/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/QuickBlox%2Fq-municate-services-ios/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/QuickBlox%2Fq-municate-services-ios/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/QuickBlox","download_url":"https://codeload.github.com/QuickBlox/q-municate-services-ios/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224470923,"owners_count":17316710,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["auth","cache","chat","contacts","dialog","easy","groupchat","ios","objective-c","pushnotificaitions","quickblox","services","users"],"created_at":"2024-11-13T15:12:51.729Z","updated_at":"2024-11-13T15:12:52.479Z","avatar_url":"https://github.com/QuickBlox.png","language":"Objective-C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# QMServices are deprecated and won't be supported.\n\n[![CocoaPods](https://img.shields.io/cocoapods/v/QMServices.svg)](https://cocoapods.org/pods/QMServices)\n[![CocoaPods](https://img.shields.io/cocoapods/dt/QMServices.svg)](https://cocoapods.org/pods/QMServices)\n[![CocoaPods](https://img.shields.io/cocoapods/dm/QMServices.svg)](https://cocoapods.org/pods/QMServices)\n\n- [QMServices](#qmservices)\n- [Features](#features)\n- [Requirements](#requirements)\n- [Dependencies](#dependencies)\n- [Installation](#installation)\n\t- [1. Cocoapods](#1-cocoapods)\n\t- [2. Using an Xcode subproject](#2-using-an-xcode-subproject)\n\t\t- [Bundle generation](#bundle-generation)\n- [Architecture](#architecture)\n- [Getting started](#getting-started)\n\t- [Service Manager](#service-manager)\n\t- [Logs](#logs)\n\t- [Authentication](#authentication)\n\t\t- [Login](#login)\n\t\t- [Logout](#logout)\n\t- [Fetching chat dialogs](#fetching-chat-dialogs)\n\t- [Fetching chat messages](#fetching-chat-messages)\n\t- [Sending message](#sending-message)\n\t- [Fetching users](#fetching-users)\n\t- [Subclass of QMServicesManager example](#qmservices-example)\n\t- [QMAuthService](#qmauthservice)\n\t\t- [QMAuthService + Bolts](#qmauthservice--bolts)\n\t- [QMChatService](#qmauthservice)\n\t\t- [QMChatService + Bolts](#qmchatservice--bolts)\n\t\t- [QMDialogsMemoryStorage](#qmdialogsmemorystorage)\n\t\t- [QMMessagesMemoryStorage](#qmmessagesmemorystorage)\n\t\t- [QMChatAttachmentService](#qmchatattachmentservice)\n\t- [QMContactListService](#qmcontactlistservice)\n\t\t- [QMContactListMemoryStorage](#qmcontactlistmemorystorage)\n\t- [QMUsersService](#qmusersservice)\n\t\t- [QMUsersMemoryStorage](#qmusersmemorystorage)\n\t\t\t- [Add users](#add-users)\n\t\t\t- [Get users](#get-users)\n\t\t\t- [Search and Exclude](#search-and-exclude)\n- [Documentation](#documentation)\n- [License](#license)\n\n# QMServices\n\nEasy-to-use services for Quickblox SDK, for speeding up development of iOS chat applications.\n\n# Features\n\n* High level API for Chat features including authentication service for logging to Quickblox REST and XMPP\n* Inbox persistent storage for messages, dialogs and users\n* Inbox memory storage for messages, dialogs and users\n* Bolts version of all methods. See [Bolts-iOS](https://github.com/BoltsFramework/Bolts-iOS \"Bolts-iOS\"\") for more information.\n\n# Requirements\n\n- Xcode 6+\n- ARC\n\n# Dependencies\n\n- [Quickblox](https://github.com/QuickBlox/quickblox-ios-sdk 'Quickblox iOS SDK') SDK 2.6.5+\n- [Bolts](https://github.com/BoltsFramework/Bolts-iOS 'Bolts-iOS') 1.5.0+\n\n# Installation\n\nThere are several ways to add **QMServices** to your project. They are described below:\n\n## 1. Cocoapods\n\nYou can install **QMServices** using Cocoapods just by adding following line in your Podfile:\n\n```\npod 'QMServices'\n```\n\n## 2. Using an Xcode subproject\n\nXcode sub-projects allow your project to use and build QMServices as an implicit dependency.\n\nAdd QMServices to your project as a Git submodule:\n\n```\n$ cd MyXcodeProjectFolder\n$ git submodule add https://github.com/QuickBlox/q-municate-services-ios.git Vendor/QMServices\n$ git commit -m \"Added QMServices submodule\"\n```\n\nThis will add QMServices as a submodule and download Bolts as dependency.\nDrag `Vendor/QMServices/QMServices.xcodeproj ` into your existing Xcode project.\n\nNavigate to your project's settings, then select the target you wish to add QMServices to.\n\nNavigate to **Build Settings**, then search for **Header Search Paths** and double-click it to edit\n\nAdd a new item using **+**: `\"$(SRCROOT)/Vendor/QMServices\"` and ensure that it is set to *recursive*\n\nNavigate to **Build Settings**, then search for **Framework Search Paths** and double-click it to edit\n\nAdd a new item using **+**: `\"$(SRCROOT)/Vendor/QMServices/Frameworks\"`\n\n\u003cp style='color:red'\u003e** NOTE**\u003c/p\u003e\n\u003cp style='color:red'\u003eOnly for manual installation: if you do not follow the steps below you will get compiler errors that Quickblox.framework and Bolts.framework are not found\u003c/p\u003e Quickblox.framework and Bolts.framework in `\"$(SRCROOT)/Vendor/QMServices/Frameworks\"` does NOT contain binary data, they used only for generating bundles. \u003cbr\u003e\nIf you plan to use QMServices as sub-project, then \u003cbr\u003e\n1. Download Quickblox.framework https://github.com/QuickBlox/quickblox-ios-sdk/archive/master.zip \u003cbr\u003e\n2. Download Bolts.framework https://github.com/BoltsFramework/Bolts-ObjC/releases/download/1.5.1/Bolts-iOS.zip \u003cbr\u003e\n3. Put the frameworks in the folder 'Vendor/QMServices/Frameworks' \u003cbr\u003e\n\n\u003e ** NOTE**: By default, *QMServices* subprojects reference Quickblox and Bolts frameworks at `../Frameworks`.\n\u003e To change the path, you need to open Quickblox.xcconfig file and replace `../Frameworks` with your path to the Quickblox.framework and Bolts.framework.\n\n\u003e ** NOTE** Please be aware that if you've set Xcode's **Link Frameworks Automatically** to **No** then you may need to add the Quickblox.framework, CoreData.framework to your project on iOS, as UIKit does not include Core Data by default. On OS X, Cocoa includes Core Data.\n\nNow navigate to QMServices.xcodeproj subproject, open **Build Settings**, search for **Framework Search Paths** and locate Quickblox and Bolts frameworks folder there.\nRemember, that you have to link *QMServices* in **Target Dependencies** and (or) *libQMServices.a* in **Link Binary with Libraries**.\nDon't forget to add Quickblox and Bolts frameworks to your project.\n\nNext step is to copy all bundles into your Copy bundle resources in Build Phases tab of your project settings.\nNavigate to QMServices.xcodeproj/Cache and move QMUsersCacheModel.bundle, QMContactListCacheModel.bundle and QMChatCacheModel.bundle that are existent in its subprojects to Copy Bundle Resources of your project. In a pop-up window select only \"Create folder references\".\n\nIf you are adding QMServices to the Swift project, you need to import them in your bridging header:\n\n```swift\n#import \"QMServices.h\"\n```\n\nTo integrate Quckblox iOS SDK into your Swift project see our detailed guide [here](http://quickblox.com/developers/IOS-how-to-connect-Quickblox-framework#Additional_steps_for_Swift_using_Manual_Installation).\n\nIf you are still experiencing some crashes, check if you have set up correct Other linker flags for your project (-lxml2, -ObjC, -lstdc++) otherwise feel free to create an issue and let us know your problem.\n\n### Bundle generation\n**NOTE:** You can skip this step if you do not use dialogs, messages and users memory and disc storage.\n\nBundle allows to pass .xcdatamodel file together with static library so it is required for **QMChatCache** and **QMContactListCache** projects.\n\nTo generate bundle for contact list you need to open **QMServices** project, navigate to Cache folder and select **QMContactListCache.xcodeproj**. Open project folder - you will see red **QMContactListCacheModel.bundle**. To create it select scheme **QMContactListCacheModel** and run it. After successful build **QMContactListCacheModel.bundle** color will change to black and you will be able to copy it to the project that uses **QMServices**. Include this bundle in your project.\n\nTo generate bundle for dialogs and messages you need to open **QMServices** project, navigate to Cache folder and select **QMChatCache.xcodeproj**. Open project folder - you will see red **QMChatCacheModel.bundle**. To create it select scheme **QMChatCacheModel** and run it. After successful build **QMChatCacheModel.bundle`** color will change to black and you will be able to copy it to the project that uses **QMServices**. Include this bundle in your project.\n\n# Architecture\n\nQMServices contain:\n\n* **QMAuthService**\n* **QMChatService**\n* **QMContactListService**\n* **QMUsersService**\n\n\nThey all inherited from **QMBaseService**.\nTo support CoreData caching you can use **QMContactListCache**, **QMChatCache** and **QMUsersCache**, which are inherited from **QMDBStorage**. Of course you could use your own database storage - just need to implement **QMChatServiceDelegate**, **QMContactListServiceDelegate** or **QMUsersServiceDelegate** depending on your needs.\n\n# Getting started\nAdd **#import \\\u003cQMServices.h\\\u003e** to your app's *.pch* file.\n\n## Service Manager\n\nTo start using services you could either use existing **QMServicesManager** class or create a subclass from it.\nDetailed explanation of the **QMServicesManager** class is below.\n\n**QMServicesManager** has 2 functions - user login(login to REST API, chat)/logout(Logging out from chat, REST API, clearing persistent and memory cache) and establishing connection between **QMChatCache** and **QMChatService** to enable storing dialogs and messages data on disc.\n\nHere is **QMServicesManager.h**:\n\n```objective-c\n@interface QMServicesManager : NSObject \u003cQMServiceManagerProtocol, QMChatServiceCacheDataSource, QMChatServiceDelegate, QMChatConnectionDelegate\u003e\n\n+ (instancetype)instance;\n\n- (void)logInWithUser:(QBUUser *)user completion:(void (^)(BOOL success, NSString *errorMessage))completion;\n- (void)logoutWithCompletion:(dispatch_block_t)completion;\n\n@property (nonatomic, readonly) QMAuthService* authService;\n@property (nonatomic, readonly) QMChatService* chatService;\n\n@end\n```\n\nAnd extension in **QMServicesManager.m**:\n\n```objective-c\n@interface QMServicesManager ()\n\n@property (nonatomic, strong) QMAuthService* authService;\n@property (nonatomic, strong) QMChatService* chatService;\n\n@property (nonatomic, strong) dispatch_group_t logoutGroup;\n\n@end\n```\n\nIn ``init`` method, services and cache are initialised.\n\n```objective-c\n- (instancetype)init {\n\tself = [super init];\n\tif (self) {\n\t\t[QMChatCache setupDBWithStoreNamed:@\"sample-cache\"];\n\t\t[QMChatCache instance].messagesLimitPerDialog = 10;\n\n\t\t_authService = [[QMAuthService alloc] initWithServiceManager:self];\n\t\t_chatService = [[QMChatService alloc] initWithServiceManager:self cacheDataSource:self];\n\t\t[_chatService addDelegate:self];\n\t\t_logoutGroup = dispatch_group_create();\n\t}\n\treturn self;\n}\n```\n\n* Cache setup (You could skip it if you don't need persistent storage).\n\n\t* Initiates Core Data database for dialog and messages:\n\n\t```objective-c\n\t[QMChatCache setupDBWithStoreNamed:@\"sample-cache\"];\n\t```\n\n* Services setup\n\n\t* Authentication service:\n\t\n\t```objective-c\n\t_authService = [[QMAuthService alloc] initWithServiceManager:self];\n\t```\n\t\n\t* Chat service (responsible for establishing chat connection and responding to chat events (message, presences and so on)):\n\n\t```objective-c\n\t_chatService = [[QMChatService alloc] initWithServiceManager:self cacheDataSource:self];\n\t```\n\t\nAlso you have to implement **QMServiceManagerProtocol** methods:\n\n```objective-c\n- (void)handleErrorResponse:(QBResponse *)response {\n\t// handle error response from services here\n}\n\n- (BOOL)isAuthorized {\n\treturn self.authService.isAuthorized;\n}\n\n- (QBUUser *)currentUser {\n\treturn [QBSession currentSession].currentUser;\n}\n```\n\nTo implement chat messages and dialogs caching you should implement following methods from **QMChatServiceDelegate** protocol:\n\n```objective-c\n- (void)chatService:(QMChatService *)chatService didAddChatDialogToMemoryStorage:(QBChatDialog *)chatDialog {\n\t[QMChatCache.instance insertOrUpdateDialog:chatDialog completion:nil];\n}\n\n- (void)chatService:(QMChatService *)chatService didAddChatDialogsToMemoryStorage:(NSArray *)chatDialogs {\n\t[QMChatCache.instance insertOrUpdateDialogs:chatDialogs completion:nil];\n}\n\n- (void)chatService:(QMChatService *)chatService didAddMessageToMemoryStorage:(QBChatMessage *)message forDialogID:(NSString *)dialogID {\n\t[QMChatCache.instance insertOrUpdateMessage:message withDialogId:dialogID completion:nil];\n}\n\n- (void)chatService:(QMChatService *)chatService didAddMessagesToMemoryStorage:(NSArray *)messages forDialogID:(NSString *)dialogID {\n\t[QMChatCache.instance insertOrUpdateMessages:messages withDialogId:dialogID completion:nil];\n}\n\n- (void)chatService:(QMChatService *)chatService didDeleteChatDialogWithIDFromMemoryStorage:(NSString *)chatDialogID {\n    [QMChatCache.instance deleteDialogWithID:chatDialogID completion:nil];\n}\n\n- (void)chatService:(QMChatService *)chatService  didReceiveNotificationMessage:(QBChatMessage *)message createDialog:(QBChatDialog *)dialog {\n\t[QMChatCache.instance insertOrUpdateMessage:message withDialogId:dialog.ID completion:nil];\n\t[QMChatCache.instance insertOrUpdateDialog:dialog completion:nil];\n}\n\n- (void)chatService:(QMChatService *)chatService didUpdateChatDialogInMemoryStorage:(QBChatDialog *)chatDialog {\n    [[QMChatCache instance] insertOrUpdateDialog:chatDialog completion:nil];\n}\n```\n\nAlso for prefetching initial dialogs and messages you have to implement **QMChatServiceCacheDataSource** protocol:\n\n```objective-c\n- (void)cachedDialogs:(QMCacheCollection)block {\n\t[QMChatCache.instance dialogsSortedBy:CDDialogAttributes.lastMessageDate ascending:YES completion:^(NSArray *dialogs) {\n\t\tblock(dialogs);\n\t}];\n}\n\n- (void)cachedMessagesWithDialogID:(NSString *)dialogID block:(QMCacheCollection)block {\n\t[QMChatCache.instance messagesWithDialogId:dialogID sortedBy:CDMessageAttributes.messageID ascending:YES completion:^(NSArray *array) {\n\t\tblock(array);\n\t}];\n}\n```\n\n## Logs\n\nBy default QMServices logging its information in developer console. You may want to disable them (for example for production, logs can slow your app sometimes). In order to do so use QMServicesManager static method:\n\n```objective-c\n+ (void)enableLogging:(BOOL)flag;\n```\n\nJust set it, for example, in your AppDelegate class like this:\n\n```objective-c\n[QMServicesManager enableLogging:NO];\n```\n\n## Authentication\n\n### Login\n\nThis method logins user to Quickblox REST API backend and to the Quickblox Chat backend. Also it automatically tries to join to all cached group dialogs - to immediately receive incomming messages.\n\n```objective-c\n- (void)logInWithUser:(QBUUser *)user\n\t\t   completion:(void (^)(BOOL success, NSString *errorMessage))completion\n{\n\t__weak typeof(self) weakSelf = self;\n\t[self.authService logInWithUser:user completion:^(QBResponse *response, QBUUser *userProfile) {\n\t\tif (response.error != nil) {\n\t\t\tif (completion != nil) {\n\t\t\t\tcompletion(NO, response.error.error.localizedDescription);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\t\n\t\t[weakSelf.chatService connectWithCompletionBlock:^(NSError * _Nullable error) {\n            //\n            __typeof(self) strongSelf = weakSelf;\n            \n            [strongSelf.chatService loadCachedDialogsWithCompletion:^{\n                NSArray* dialogs = [strongSelf.chatService.dialogsMemoryStorage unsortedDialogs];\n                for (QBChatDialog* dialog in dialogs) {\n                    if (dialog.type != QBChatDialogTypePrivate) {\n                        [strongSelf.chatService joinToGroupDialog:dialog completion:^(NSError * _Nullable error) {\n                            //\n                            if (error != nil) {\n                                NSLog(@\"Join error: %@\", error.localizedDescription);\n                            }\n                        }];\n                    }\n                }\n                \n                if (completion != nil) {\n                    completion(error == nil, error.localizedDescription);\n                }\n                \n            }];\n        }];\n\t}];\n}\n\n\n```\n\nExample of usage:\n\n```objective-c\n    // Logging in to Quickblox REST API and chat.\n    [QMServicesManager.instance logInWithUser:selectedUser completion:^(BOOL success, NSString *errorMessage) {\n        if (success) {\n            // Handle success login\n        } else {\n            // Handle error with error message\n        }\n    }];\n```\n\n### Logout\n\n```objective-c\n- (void)logoutWithCompletion:(dispatch_block_t)completion\n{\n    if ([QBSession currentSession].currentUser != nil) {\n        __weak typeof(self)weakSelf = self;\n                \n        dispatch_group_enter(self.logoutGroup);\n        [self.authService logOut:^(QBResponse *response) {\n            __typeof(self) strongSelf = weakSelf;\n            [strongSelf.chatService disconnectWithCompletionBlock:nil];\n            [strongSelf.chatService free];\n            dispatch_group_leave(strongSelf.logoutGroup);\n        }];\n        \n        dispatch_group_enter(self.logoutGroup);\n        [[QMChatCache instance] deleteAllDialogsWithCompletion:^{\n            __typeof(self) strongSelf = weakSelf;\n            dispatch_group_leave(strongSelf.logoutGroup);\n        }];\n        \n        dispatch_group_enter(self.logoutGroup);\n        [[QMChatCache instance] deleteAllMessagesWithCompletion:^{\n            __typeof(self) strongSelf = weakSelf;\n            dispatch_group_leave(strongSelf.logoutGroup);\n        }];\n        \n        dispatch_group_notify(self.logoutGroup, dispatch_get_main_queue(), ^{\n            if (completion) {\n                completion();\n            }\n        });\n    } else {\n        if (completion) {\n            completion();\n        }\n    }\n}\n```\n\nExample of usage:\n\n```objective-c\n    [[QMServicesManager instance] logoutWithCompletion:^{\n        // Handle logout\n    }];\n```\n\n## Fetching chat dialogs\n\nLoad all dialogs from REST API:\n\nExtended request parameters could be taken from http://quickblox.com/developers/SimpleSample-chat_users-ios#Filters.\n\n```objective-c\n\n[QMServicesManager.instance.chatService allDialogsWithPageLimit:100 extendedRequest:nil iterationBlock:^(QBResponse *response, NSArray *dialogObjects, NSSet *dialogsUsersIDs, BOOL *stop) {\n\t// reload UI, this block is called when page is loaded\n} completion:^(QBResponse *response) {\n\t// loading finished, all dialogs fetched\n}];\n```\n\nThese dialogs are automatically stored in **QMDialogsMemoryStorage** class.\n\n## Fetching chat messages\n\nFetching messages from REST API history:\n\n```objective-c\n[QMServicesManager instance].chatService messagesWithChatDialogID:@\"53fdc87fe4b0f91d92fbb27e\" completion:^(QBResponse *response, NSArray *messages) {\n\t// update UI, handle messages\n}];\n```\n\nThese message are automatically stored in **QMMessagesMemoryStorage** class.\n\n## Sending message\n\nSend message to dialog:\n\n```objective-c\n\nQBChatMessage *message = [QBChatMessage message];\nmessage.text = @\"Awesome text\";\nmessage.senderID = 2308497;\n\n[[QMServicesManager instance].chatService sendMessage:message type:QMMessageTypeText toDialogId:@\"53fdc87fe4b0f91d92fbb27e\" saveToHistory:YES saveToStorage:YES completion:nil];\n```\n\nMessage is automatically added to **QMMessagesMemoryStorage** class.\n\n## Fetching users\n\n\n```objective-c\n[[[QMServicesManager instance].usersService getUsersWithIDs:@[@(2308497), @(2308498)]] continueWithBlock:^id(BFTask\u003cNSArray\u003cQBUUser *\u003e *\u003e *task) {\n        if (task.error == nil) {\n            // handle users\n        }\n        return nil;\n}];\n```\n\nUsers are automatically stored in **QMUsersMemoryStorage** class.\n\n## Subclass of QMServicesManager example\n\nThis example adds additional functionality - storing of users in contact list cache, error handling, storing currently opened dialog identifier.\n\nHeader file:\n\n```objective-c\n@interface ServicesManager : QMServicesManager \u003cQMContactListServiceCacheDataSource\u003e\n\n// Replaces with any users service you are already using or going to use\n@property (nonatomic, readonly) UsersService* usersService;\n\n@property (nonatomic, strong) NSString* currentDialogID;\n\n@end\n\n```\n\nImplementation file:\n\n```objective-c\n@interface ServicesManager ()\n\n@property (nonatomic, strong) QMContactListService* contactListService;\n\n@end\n\n@implementation ServicesManager\n\n- (instancetype)init {\n\tself = [super init];\n    \n\tif (self) {\n        [QMContactListCache setupDBWithStoreNamed:kContactListCacheNameKey];\n\t\t_contactListService = [[QMContactListService alloc] initWithServiceManager:self cacheDataSource:self];\n\t\t// Replace with any users service you are already using or going to use\n\t\t_usersService = [[UsersService alloc] initWithContactListService:_contactListService];\n\t}\n    \n\treturn self;\n}\n\n- (void)showNotificationForMessage:(QBChatMessage *)message inDialogID:(NSString *)dialogID\n{\n    if ([self.currentDialogID isEqualToString:dialogID]) return;\n    \n    if (message.senderID == self.currentUser.ID) return;\n    \n    NSString* dialogName = @\"New message\";\n    \n    QBChatDialog* dialog = [self.chatService.dialogsMemoryStorage chatDialogWithID:dialogID];\n    \n    if (dialog.type != QBChatDialogTypePrivate) {\n        dialogName = dialog.name;\n    } else {\n        QBUUser* user = [[StorageManager instance] userByID:dialog.recipientID];\n        if (user != nil) {\n            dialogName = user.login;\n        }\n    }\n    \n    // Display notification UI\n}\n\n- (void)handleErrorResponse:(QBResponse *)response {\n    \n    [super handleErrorResponse:response];\n    \n    if (![self isAuthorized]) return;\n\tNSString *errorMessage = [[response.error description] stringByReplacingOccurrencesOfString:@\"(\" withString:@\"\"];\n\terrorMessage = [errorMessage stringByReplacingOccurrencesOfString:@\")\" withString:@\"\"];\n\t\n\tif( response.status == 502 ) { // bad gateway, server error\n\t\terrorMessage = @\"Bad Gateway, please try again\";\n\t}\n\telse if( response.status == 0 ) { // bad gateway, server error\n\t\terrorMessage = @\"Connection network error, please try again\";\n\t}\n    \n    // Display notification UI\n}\n\n#pragma mark QMChatServiceCache delegate\n\n- (void)chatService:(QMChatService *)chatService didAddMessageToMemoryStorage:(QBChatMessage *)message forDialogID:(NSString *)dialogID {\n    [super chatService:chatService didAddMessageToMemoryStorage:message forDialogID:dialogID];\n    \n    [self showNotificationForMessage:message inDialogID:dialogID];\n}\n\n#pragma mark QMContactListServiceCacheDelegate delegate\n\n- (void)cachedUsers:(QMCacheCollection)block {\n\t[QMContactListCache.instance usersSortedBy:@\"id\" ascending:YES completion:block];\n}\n\n- (void)cachedContactListItems:(QMCacheCollection)block {\n\t[QMContactListCache.instance contactListItems:block];\n}\n\n@end\n```\n\n## QMAuthService\n\nThis class is responsible for authentication operations.\n\nCurrent user authorisation status:\n\n```objective-c\n\n@property (assign, nonatomic, readonly) BOOL isAuthorized;\n\n```\n\nSign up user and login to Quickblox.\n\n```objective-c\n\n- (QBRequest *)signUpAndLoginWithUser:(QBUUser *)user completion:(void(^)(QBResponse *response, QBUUser *userProfile))completion;\n\n```\n\nLogin user to Quickblox.\n\n```objective-c\n\n- (QBRequest *)logInWithUser:(QBUUser *)user completion:(void(^)(QBResponse *response, QBUUser *userProfile))completion;\n\n```\n\nLogin with facebook session token.\n\n```objective-c\n\n- (QBRequest *)logInWithFacebookSessionToken:(NSString *)sessionToken completion:(void(^)(QBResponse *response, QBUUser *userProfile))completion;\n\n```\n\nLogout user from Quickblox.\n\n```objective-c\n\n- (QBRequest *)logInWithFacebookSessionToken:(NSString *)sessionToken completion:(void(^)(QBResponse *response, QBUUser *userProfile))completion;\n\n```\n\n### QMAuthService + Bolts \n\nQMAuthService also has all methods implemented using BFTasks.\n\nSign up user and log's in to Quickblox using Bolts.\n\n```objective-c\n\n- (BFTask *)signUpAndLoginWithUser:(QBUUser *)user;\n\n```\n\nLogin user to Quickblox using Bolts.\n\n```objective-c\n\n- (BFTask *)loginWithUser:(QBUUser *)user;\n\n```\n\nLogin with facebook session token using Bolts.\n\n```objective-c\n\n- (BFTask *)loginWithFacebookSessionToken:(NSString *)sessionToken;\n\n```\n\nLogout user from Quickblox using Bolts.\n\n```objective-c\n\n- (BFTask *)logout;\n\n```\n\n## QMChatService\n\nThis class is responsible for operation with messages and dialogs.\n\nConnect user to Quickblox chat.\n\n```objective-c\n\n- (void)connectWithCompletionBlock:(QBChatCompletionBlock)completion;\n\n```\n\nDisconnect user from Quickblox chat.\n\n```objective-c\n\n- (void)disconnectWithCompletionBlock:(QBChatCompletionBlock)completion;\n\n```\n\nJoin user to group dialog.\n\n```objective-c\n\n- (void)joinToGroupDialog:(QBChatDialog *)dialog completion:(QBChatCompletionBlock)completion;\n\n```\n\nCreate group chat dialog with occupants on Quickblox.\n\n```objective-c\n\n- (void)createGroupChatDialogWithName:(NSString *)name photo:(NSString *)photo occupants:(NSArray *)occupants\ncompletion:(void(^)(QBResponse *response, QBChatDialog *createdDialog))completion;\n\n```\n\nCreate private chat dialog with opponent on Quickblox.\n\n```objective-c\n\n- (void)createPrivateChatDialogWithOpponent:(QBUUser *)opponent\ncompletion:(void(^)(QBResponse *response, QBChatDialog *createdDialog))completion;\n\n```\n\nChange dialog name.\n\n```objective-c\n\n- (void)changeDialogName:(NSString *)dialogName forChatDialog:(QBChatDialog *)chatDialog\ncompletion:(void(^)(QBResponse *response, QBChatDialog *updatedDialog))completion;\n\n```\n\nChange dialog avatar.\n\n```objective-c\n\n- (void)changeDialogAvatar:(NSString *)avatarPublicUrl forChatDialog:(QBChatDialog *)chatDialog\ncompletion:(void(^)(QBResponse *response, QBChatDialog *updatedDialog))completion;\n\n```\n\nAdd occupants to dialog.\n\n``` objective-c\n\n- (void)joinOccupantsWithIDs:(NSArray *)ids toChatDialog:(QBChatDialog *)chatDialog\ncompletion:(void(^)(QBResponse *response, QBChatDialog *updatedDialog))completion;\n\n\n```\n\n\nDeletes dialog on service and in cache.\n\n```objective-c\n\n- (void)deleteDialogWithID:(NSString *)dialogId\ncompletion:(void(^)(QBResponse *response))completion;\n\n```\n\nRecursively fetch all dialogs from Quickblox.\n\n```objective-c\n\n- (void)allDialogsWithPageLimit:(NSUInteger)limit\n\t\t\t\textendedRequest:(NSDictionary *)extendedRequest\n\t\t\t\t iterationBlock:(void(^)(QBResponse *response, NSArray *dialogObjects, NSSet *dialogsUsersIDs, BOOL *stop))iterationBlock\n\t\t\t\t\t completion:(void(^)(QBResponse *response))completion;\n```\n\nSend system message to users about adding to dialog with dialog inside.\n\n```objective-c\n\n- (void)sendSystemMessageAboutAddingToDialog:(QBChatDialog *)chatDialog\n                                  toUsersIDs:(NSArray *)usersIDs\n                                  completion:(QBChatCompletionBlock)completion;\n\n```\n\nSend message about updated dialog with dialog inside and notification.\n\n```objective-c\n\n- (void)sendMessageAboutUpdateDialog:(QBChatDialog *)updatedDialog\n                withNotificationText:(NSString *)notificationText\n                    customParameters:(NSDictionary *)customParameters\n                          completion:(QBChatCompletionBlock)completion;\n\n```\n\nSend message about accepting or rejecting contact requst.\n\n```objective-c\n\n- (void)sendMessageAboutAcceptingContactRequest:(BOOL)accept\n                                   toOpponentID:(NSUInteger)opponentID\n                                     completion:(QBChatCompletionBlock)completion;\n\n```\n\nSending notification message about adding occupants to specific dialog.\n\n```objective-c\n\n- (void)sendNotificationMessageAboutAddingOccupants:(NSArray *)occupantsIDs\n                                           toDialog:(QBChatDialog *)chatDialog\n                               withNotificationText:(NSString *)notificationText\n                                         completion:(QBChatCompletionBlock)completion;\n                                         \n```\n\nSending notification message about leaving dialog.\n\n```objective-c\n\n- (void)sendNotificationMessageAboutLeavingDialog:(QBChatDialog *)chatDialog\n                             withNotificationText:(NSString *)notificationText\n                                       completion:(QBChatCompletionBlock)completion;\n                                         \n```\n\nSending notification message about changing dialog photo.\n\n```objective-c\n\n- (void)sendNotificationMessageAboutChangingDialogPhoto:(QBChatDialog *)chatDialog\n                                   withNotificationText:(NSString *)notificationText\n                                             completion:(QBChatCompletionBlock)completion;\n                                         \n```\n\nSending notification message about changing dialog name.\n\n```objective-c\n\n- (void)sendNotificationMessageAboutChangingDialogName:(QBChatDialog *)chatDialog\n                                  withNotificationText:(NSString *)notificationText\n                                            completion:(QBChatCompletionBlock)completion;\n                                         \n```\n\nFetches 100 messages starting from latest message in cache.\n\n```objective-c\n\n- (void)messagesWithChatDialogID:(NSString *)chatDialogID completion:(void(^)(QBResponse *response, NSArray *messages))completion;\n\n```\n\nFetches 100 messages that are older than oldest message in cache.\n\n```objective-c\n\n- (BFTask \u003cNSArray \u003cQBChatMessage *\u003e *\u003e *)loadEarlierMessagesWithChatDialogID:(NSString *)chatDialogID;\n\n```\n\nFetch dialog with dialog identifier.\n\n```objective-c\n\n- (void)fetchDialogWithID:(NSString *)dialogID completion:(void (^)(QBChatDialog *dialog))completion;\n\n```\n\nLoad dialog with dialog identifier from Quickblox server and save to local storage.\n\n```objective-c\n\n- (void)loadDialogWithID:(NSString *)dialogID completion:(void (^)(QBChatDialog *loadedDialog))completion;\n\n```\n\nFetch dialogs updated from date.\n\n```objective-c\n\n- (void)fetchDialogsUpdatedFromDate:(NSDate *)date\n \t\t\t\t\t   andPageLimit:(NSUInteger)limit\n \t\t\t\t\t iterationBlock:(void(^)(QBResponse *response, NSArray *dialogObjects, NSSet *dialogsUsersIDs, BOOL *stop))iteration\n \t\t\t\t\tcompletionBlock:(void (^)(QBResponse *response))completion;\n\n```\n\nSend message to dialog.\n\n```objective-c\n\n- (void)sendMessage:(QBChatMessage *)message\n\t\t   toDialog:(QBChatDialog *)dialog\n      saveToHistory:(BOOL)saveToHistory\n      saveToStorage:(BOOL)saveToStorage\n         completion:(QBChatCompletionBlock)completion;\n\n```\n\nSend attachment message to dialog.\n\n```objective-c\n\n- (void)sendAttachmentMessage:(QBChatMessage *)attachmentMessage\n                     toDialog:(QBChatDialog *)dialog\n          withAttachmentImage:(UIImage *)image\n                   completion:(QBChatCompletionBlock)completion;\n\n```\n\nMark message as delivered.\n\n```objective-c\n\n- (void)markMessageAsDelivered:(QBChatMessage *)message completion:(QBChatCompletionBlock)completion;\n\n```\n\nMark messages as delivered.\n\n```objective-c\n\n- (void)markMessagesAsDelivered:(NSArray\u003cQBChatMessage *\u003e *)messages completion:(QBChatCompletionBlock)completion;\n\n```\n\nSend read status for message and update unreadMessageCount for dialog in storage.\n\n```objective-c\n\n- (void)readMessage:(QBChatMessage *)message completion:(QBChatCompletionBlock)completion;\n\n```\n\nSend read status for messages and update unreadMessageCount for dialog in storage.\n\n```objective-c\n\n- (void)readMessages:(NSArray\u003cQBChatMessage *\u003e *)messages forDialogID:(NSString *)dialogID completion:(QBChatCompletionBlock)completion;\n\n```\n\n### QMChatService + Bolts \n\nQMChatService also has all methods implemented using BFTasks.\n\nConnect user to Quickblox chat using Bolts.\n\n```objective-c\n\n- (BFTask *)connect;\n\n```\n\nDisconnect user from Quickblox chat using Bolts.\n\n```objective-c\n\n- (BFTask *)disconnect;\n\n```\n\nJoin user to group dialog using Bolts.\n\n```objective-c\n\n- (BFTask *)joinToGroupDialog:(QBChatDialog *)dialog;\n\n```\n\nCreate group chat dialog with occupants on Quickblox using Bolts.\n\n```objective-c\n\n- (BFTask *)createGroupChatDialogWithName:(NSString *)name photo:(NSString *)photo occupants:(NSArray *)occupants;\n\n```\n\nCreate private chat dialog with opponent on Quickblox using Bolts.\n\n```objective-c\n\n- (BFTask *)createPrivateChatDialogWithOpponent:(QBUUser *)opponent;\n\n```\n\nChange dialog name using Bolts.\n\n```objective-c\n\n- (BFTask *)changeDialogName:(NSString *)dialogName forChatDialog:(QBChatDialog *)chatDialog;\n\n```\n\nChange dialog avatar using Bolts.\n\n```objective-c\n\n- (BFTask *)changeDialogAvatar:(NSString *)avatarPublicUrl forChatDialog:(QBChatDialog *)chatDialog;\n\n```\n\nAdd occupants to dialog using Bolts.\n\n``` objective-c\n\n- (BFTask *)joinOccupantsWithIDs:(NSArray *)ids toChatDialog:(QBChatDialog *)chatDialog;\n\n```\n\nDeletes dialog on service and in cache using Bolts.\n\n```objective-c\n\n- (BFTask *)deleteDialogWithID:(NSString *)dialogID;\n\n```\n\nRecursively fetch all dialogs from Quickblox using Bolts.\n\n```objective-c\n\n- (BFTask *)allDialogsWithPageLimit:(NSUInteger)limit\n                    extendedRequest:(NSDictionary *)extendedRequest\n                     iterationBlock:(void(^)(QBResponse *response, NSArray *dialogObjects, NSSet *dialogsUsersIDs, BOOL *stop))iterationBlock;\n\n```\n\nSend system message to users about adding to dialog with dialog inside using Bolts.\n\n```objective-c\n\n- (BFTask *)sendSystemMessageAboutAddingToDialog:(QBChatDialog *)chatDialog\n                                      toUsersIDs:(NSArray *)usersIDs;\n\n```\n\nSend message about accepting or rejecting contact requst using Bolts.\n\n```objective-c\n\n- (BFTask *)sendMessageAboutAcceptingContactRequest:(BOOL)accept\n                                       toOpponentID:(NSUInteger)opponentID;\n\n```\n\nSending notification message about adding occupants to specific dialog using Bolts.\n\n```objective-c\n\n- (BFTask *)sendNotificationMessageAboutAddingOccupants:(NSArray *)occupantsIDs\n                                               toDialog:(QBChatDialog *)chatDialog\n                                   withNotificationText:(NSString *)notificationText;\n                                         \n```\n\nSending notification message about leaving dialog using Bolts.\n\n```objective-c\n\n- (BFTask *)sendNotificationMessageAboutLeavingDialog:(QBChatDialog *)chatDialog\n                                 withNotificationText:(NSString *)notificationText;\n                                         \n```\n\nSending notification message about changing dialog photo using Bolts.\n\n```objective-c\n\n- (BFTask *)sendNotificationMessageAboutChangingDialogPhoto:(QBChatDialog *)chatDialog\n                                       withNotificationText:(NSString *)notificationText;\n                                         \n```\n\nSending notification message about changing dialog name using Bolts.\n\n```objective-c\n\n- (BFTask *)sendNotificationMessageAboutChangingDialogName:(QBChatDialog *)chatDialog\n                                      withNotificationText:(NSString *)notificationText;\n                                         \n```\n\nFetches messages with chat dialog ID using Bolts.\n\n```objective-c\n\n- (BFTask *)messagesWithChatDialogID:(NSString *)chatDialogID;\n\n```\n\nFetch dialog with dialog identifier using Bolts.\n\n```objective-c\n\n- (BFTask *)fetchDialogWithID:(NSString *)dialogID;\n\n```\n\nLoad dialog with dialog identifier from Quickblox server and save to local storage using Bolts.\n\n```objective-c\n\n- (BFTask *)loadDialogWithID:(NSString *)dialogID;\n\n```\n\nFetch dialogs updated from date using Bolts.\n\n```objective-c\n\n- (BFTask *)fetchDialogsUpdatedFromDate:(NSDate *)date\n                           andPageLimit:(NSUInteger)limit\n                         iterationBlock:(void(^)(QBResponse *response, NSArray *dialogObjects, NSSet *dialogsUsersIDs, BOOL *stop))iteration;\n\n```\n\nSend message to dialog using Bolts.\n\n```objective-c\n\n- (BFTask *)sendMessage:(QBChatMessage *)message\n               toDialog:(QBChatDialog *)dialog\n          saveToHistory:(BOOL)saveToHistory\n          saveToStorage:(BOOL)saveToStorage;\n\n```\n\nSend attachment message to dialog using Bolts.\n\n```objective-c\n\n- (BFTask *)sendAttachmentMessage:(QBChatMessage *)attachmentMessage\n                         toDialog:(QBChatDialog *)dialog\n              withAttachmentImage:(UIImage *)image;\n\n```\n\nMark message as delivered using Bolts.\n\n```objective-c\n\n- (BFTask *)markMessageAsDelivered:(QBChatMessage *)message;\n\n```\n\nSend read status for message and update unreadMessageCount for dialog in storage using Bolts.\n\n```objective-c\n\n- (BFTask *)readMessage:(QBChatMessage *)message;\n\n```\n\n### QMDialogsMemoryStorage\n\nThis class is responsible for in-memory dialogs storage.\n\nAdds chat dialog and joins if chosen.\n\n```objective-c\n\n- (void)addChatDialog:(QBChatDialog *)chatDialog andJoin:(BOOL)join completion:(void(^)(QBChatDialog *addedDialog, NSError *error))completion;\n\n```\n\nAdds chat dialogs and joins.\n\n```objective-c\n\n- (void)addChatDialogs:(NSArray *)dialogs andJoin:(BOOL)join;\n\n```\n\nDeletes chat dialog.\n\n```objective-c\n\n- (void)deleteChatDialogWithID:(NSString *)chatDialogID;\n\n```\n\nFind dialog by identifier.\n\n```objective-c\n\n- (QBChatDialog *)chatDialogWithID:(NSString *)dialogID;\n\n```\n\nFind private chat dialog with opponent ID.\n\n```objective-c\n\n- (QBChatDialog *)privateChatDialogWithOpponentID:(NSUInteger)opponentID;\n\n```\n\nFind unread dialogs.\n\n```objective-c\n\n- (NSArray *)unreadDialogs;\n\n```\n\nFetch all dialogs.\n\n```objective-c\n\n- (NSArray *)unsortedDialogs;\n\n```\n\nFetch all dialogs sorted by last message date.\n\n```objective-c\n\n- (NSArray *)dialogsSortByLastMessageDateWithAscending:(BOOL)ascending;\n\n```\n\nFetch all dialogs sorted by updated at.\n\n```objective-c\n\n- (NSArray *)dialogsSortByUpdatedAtWithAscending:(BOOL)ascending;\n\n```\n\nFetch dialogs with specified sort descriptors.\n\n```objective-c\n\n- (NSArray *)dialogsWithSortDescriptors:(NSArray *)descriptors;\n\n```\n\n### QMMessagesMemoryStorage\n\nThis class is responsible for in-memory messages storage.\n\nAdd message.\n\n```objective-c\n\n- (void)addMessage:(QBChatMessage *)message forDialogID:(NSString *)dialogID;\n\n```\n\nAdd messages.\n\n```objective-c\n\n- (void)addMessages:(NSArray *)messages forDialogID:(NSString *)dialogID;\n\n```\n\nReplace all messages for dialog.\n\n```objective-c\n\n- (void)replaceMessages:(NSArray *)messages forDialogID:(NSString *)dialogID;\n\n```\n\nUpdate message.\n\n```objective-c\n\n- (void)updateMessage:(QBChatMessage *)message;\n\n```\n\nFetch messages.\n\n```objective-c\n\n- (NSArray *)messagesWithDialogID:(NSString *)dialogID;\n\n```\n\nDelete messages for dialog.\n\n```objective-c\n\n- (void)deleteMessagesWithDialogID:(NSString *)dialogID;\n\n```\n\nFetch message by identifier.\n\n```objective-c\n\n- (QBChatMessage *)messageWithID:(NSString *)messageID fromDialogID:(NSString *)dialogID;\n\n```\n\nFetch last message.\n\n```objective-c\n\n- (QBChatMessage *)lastMessageFromDialogID:(NSString *)dialogID;\n\n```\n\nChecks if dialog has messages.\n\n```objective-c\n\n- (BOOL)isEmptyForDialogID:(NSString *)dialogID;\n\n```\n\nFetch oldest(first) message.\n\n```objective-c\n\n- (QBChatMessage *)oldestMessageForDialogID:(NSString *)dialogID;\n\n```\n\n### QMChatAttachmentService\n\nThis class is responsible for attachment operations (sending, receiving, loading, saving).\n\nAttachment status delegate:\n\n```objective-c\n\n@property (nonatomic, weak) id\u003cQMChatAttachmentServiceDelegate\u003e delegate;\n\n```\n\nGet attachment image. (Download from Quickblox or load from disc).\n\n```objective-c\n\n- (void)getImageForAttachmentMessage:(QBChatMessage *)attachmentMessage completion:(void(^)(NSError *error, UIImage *image))completion;\n\n```\n\n## QMContactListService\n\nThis class is responsible for contact list operations.\n\nAdd user to contact list.\n\n```objective-c\n\n- (void)addUserToContactListRequest:(QBUUser *)user completion:(void(^)(BOOL success))completion;\n\n```\n\nRemove user from contact list.\n\n```objective-c\n\n- (void)removeUserFromContactListWithUserID:(NSUInteger)userID completion:(void(^)(BOOL success))completion;\n\n```\n\nAccept contact request.\n\n```objective-c\n\n- (void)acceptContactRequest:(NSUInteger)userID completion:(void (^)(BOOL success))completion;\n\n```\n\nReject contact request.\n\n```objective-c\n\n- (void)rejectContactRequest:(NSUInteger)userID completion:(void(^)(BOOL success))completion;\n\n```\n\n### QMContactListMemoryStorage\n\nThis class is responsible for in-memory contact list storage.\n\nUpdate contact list memory storage.\n\n```objective-c\n\n- (void)updateWithContactList:(QBContactList *)contactList;\n\n```\n\nUpdate contact list memory storage with array of contact list items.\n\n```objective-c\n\n- (void)updateWithContactList:(QBContactList *)contactList;\n\n```\n\nFetch contact list item.\n\n```objective-c\n\n- (QBContactListItem *)contactListItemWithUserID:(NSUInteger)userID;\n\n```\n\nFetch user ids from contact list memory storage.\n\n```objective-c\n\n- (NSArray *)userIDsFromContactList;\n\n```\n\n## QMUsersService\n\nThis class is responsible for operations with users and uses [BFTasks](https://github.com/BoltsFramework/Bolts-iOS \"Bolts-iOS\").\n\nLoad users to memory storage from disc cache.\n\n```objective-c\n\n- (BFTask\u003cNSArray\u003cQBUUser *\u003e *\u003e *)loadFromCache;\n\n```\n\n###Get users\n\nThere are several ways to get users by methods below. By default every get method first checking for a specific user in cache. If such user was found in cache method will exclude him from server request, and send request only for users, that weren't found in local cache.  If you want to update users in cache, you need to force them to be loaded from server, even though they are already being cached.\nEvery get method has also its implementation with forceLoad flag, set it to YES in order to force users loading from server.\n\nGet user by id:\n\n```objective-c\n\n- (BFTask\u003cQBUUser *\u003e *)getUserWithID:(NSUInteger)userID;\n\n```\n\nGet users by ids:\n\n```objective-c\n\n- (BFTask\u003cNSArray\u003cQBUUser *\u003e *\u003e *)getUsersWithIDs:(NSArray\u003cNSNumber *\u003e *)usersIDs;\n\n```\n\nGet users by ids with extended pagination parameters:\n\n```objective-c\n\n- (BFTask\u003cNSArray\u003cQBUUser *\u003e *\u003e *)getUsersWithIDs:(NSArray\u003cNSNumber *\u003e *)usersIDs page:(QBGeneralResponsePage *)page;\n\n```\n\nGet users by emails:\n\n```objective-c\n\n- (BFTask\u003cNSArray\u003cQBUUser *\u003e *\u003e *)getUsersWithEmails:(NSArray\u003cNSString *\u003e *)emails;\n\n```\n\nGet users by emails with extended pagination parameters:\n\n```objective-c\n\n- (BFTask\u003cNSArray\u003cQBUUser *\u003e *\u003e *)getUsersWithEmails:(NSArray\u003cNSString *\u003e *)emails page:(QBGeneralResponsePage *)page;\n\n```\n\nGet users by facebook ids:\n\n```objective-c\n\n- (BFTask\u003cNSArray\u003cQBUUser *\u003e *\u003e *)getUsersWithFacebookIDs:(NSArray\u003cNSString *\u003e *)facebookIDs;\n\n```\n\nGet users by facebook ids with extended pagination parameters:\n\n```objective-c\n\n- (BFTask\u003cNSArray\u003cQBUUser *\u003e *\u003e *)getUsersWithFacebookIDs:(NSArray\u003cNSString *\u003e *)facebookIDs page:(QBGeneralResponsePage *)page;\n\n```\n\nGet users by logins:\n\n```objective-c\n\n- (BFTask\u003cNSArray\u003cQBUUser *\u003e *\u003e *)getUsersWithLogins:(NSArray\u003cNSString *\u003e *)logins;\n\n```\n\nGet users by logins with extended pagination parameters:\n\n```objective-c\n\n- (BFTask\u003cNSArray\u003cQBUUser *\u003e *\u003e *)getUsersWithLogins:(NSArray\u003cNSString *\u003e *)logins page:(QBGeneralResponsePage *)page;\n\n```\n\n###Search users\n\nSearch for users by full name:\n\n```objective-c\n\n- (BFTask\u003cNSArray\u003cQBUUser *\u003e *\u003e *)searchUsersWithFullName:(NSString *)searchText;\n\n```\n\nSearch for users by full name with extended pagination parameters:\n\n```objective-c\n\n- (BFTask\u003cNSArray\u003cQBUUser *\u003e *\u003e *)searchUsersWithFullName:(NSString *)searchText page:(QBGeneralResponsePage *)page;\n\n```\n\nSearch for users by tags:\n\n```objective-c\n\n- (BFTask\u003cNSArray\u003cQBUUser *\u003e *\u003e *)searchUsersWithTags:(NSArray\u003cNSString *\u003e *)tags;\n\n```\n\nSearch for users by tags with extended pagination parameters:\n\n```objective-c\n\n- (BFTask\u003cNSArray\u003cQBUUser *\u003e *\u003e *)searchUsersWithTags:(NSArray\u003cNSString *\u003e *)tags page:(QBGeneralResponsePage *)page;\n\n```\n\n### QMUsersMemoryStorage\n\nThis class is responsible for in-memory users storage.\n\nDelegate for getting UsersMemoryStorage user ids.\n\n```objective-c\n\n@property (weak, nonatomic) id \u003cQMUsersMemoryStorageDelegate\u003e delegate;\n\n```\n\n#### Add users\n\nAdd user to memory storage.\n\n```objective-c\n\n- (void)addUser:(QBUUser *)user;\n\n```\n\nAdd users to memory storage.\n\n```objective-c\n\n- (void)addUsers:(NSArray\u003cQBUUser *\u003e *)users;\n\n```\n\n#### Get users\n\nGet all users from memory storage without sorting.\n\n```objective-c\n\n- (NSArray\u003cQBUUser *\u003e *)unsortedUsers;\n\n```\n\nGet all users in memory storage sorted by key.\n\n```objective-c\n\n- (NSArray\u003cQBUUser *\u003e *)usersSortedByKey:(NSString *)key ascending:(BOOL)ascending;\n\n```\n\nGet all contacts in memory storage sorted by key.\n\n```objective-c\n\n- (NSArray *)contactsSortedByKey:(NSString *)key ascending:(BOOL)ascending;\n\n```\n\nGet users with ids without some id.\n\n```objective-c\n\n- (NSArray\u003cQBUUser *\u003e *)usersWithIDs:(NSArray *)IDs withoutID:(NSUInteger)ID;\n\n```\n\nGet string created from users full names, separated by \",\".\n\n```objective-c\n\n- (NSString *)joinedNamesbyUsers:(NSArray *)users;\n\n```\n\nGet user with user id.\n\n```objective-c\n\n- (QBUUser *)userWithID:(NSUInteger)userID;\n\n```\n\nGet users with user ids.\n\n```objective-c\n\n- (NSArray\u003cQBUUser *\u003e *)usersWithIDs:(NSArray *)ids;\n\n```\n\nGet users with user logins.\n\n```objective-c\n\n- (NSArray\u003cQBUUser *\u003e *)usersWithLogins:(NSArray\u003cNSString *\u003e *)logins;\n\n```\n\nGet users with user emails.\n\n```objective-c\n\n- (NSArray\u003cQBUUser *\u003e *)usersWithEmails:(NSArray\u003cNSString *\u003e *)emails;\n\n```\n\nGet users with user facebook ids.\n\n```objective-c\n\n- (NSArray\u003cQBUUser *\u003e *)usersWithFacebookIDs:(NSArray\u003cNSString *\u003e *)facebookIDs;\n\n```\n\n#### Search and Exclude\nSearch for users excluding users with users ids. Result dictionary will contain an array of found users, and an array of not found search criteria (ids, logins, emails etc).\n\n```objective-c\n\n- (NSDictionary *)usersByExcludingUsersIDs:(NSArray\u003cNSNumber *\u003e *)ids;\n\n```\n\nSearch for users excluding users with logins.\n\n```objective-c\n\n- (NSDictionary *)usersByExcludingLogins:(NSArray\u003cNSString *\u003e *)logins;\n\n```\n\nSearch for users excluding users with email.\n\n```objective-c\n\n- (NSDictionary *)usersByExcludingEmails:(NSArray\u003cNSString *\u003e *)emails;\n\n```\n\nSearch for users excluding users with facebook IDs.\n\n```objective-c\n\n- (NSDictionary *)usersByExcludingFacebookIDs:(NSArray\u003cNSString *\u003e *)facebookIDs;\n\n```\n\n# Documentation\n\nFor more information see our inline code documentation.\n\n# License\n\nSee [LICENSE.txt](LICENSE.txt)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fquickblox%2Fq-municate-services-ios","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fquickblox%2Fq-municate-services-ios","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fquickblox%2Fq-municate-services-ios/lists"}