- 充值页面

- 充值页面返回挽留弹窗
- 圈子一级页面接口数据接入
- openIM sdk 接入
- IM 会话列表
This commit is contained in:
linshujie 2026-06-04 18:36:47 +08:00
parent c0df6013fc
commit a2e352aaf0
270 changed files with 31076 additions and 11129 deletions

BIN
3.4- 圈子聊天.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 KiB

View File

@ -43,7 +43,8 @@ target 'QuickLocation' do
#第三方SDk
pod 'GYSDK' #个推一键登录
pod 'OpenIMSDK' #OpenIM
#高德地图
pod 'AMap3DMap' #3D地图SDK
pod 'AMapSearch' #地图SDK搜索功能

View File

@ -82,12 +82,44 @@ PODS:
- MarqueeLabel (4.5.3)
- Masonry (1.1.0)
- MBProgressHUD (1.2.0)
- MJExtension (3.4.2)
- MJRefresh (3.7.9)
- Moya (15.0.0):
- Moya/Core (= 15.0.0)
- Moya/Core (15.0.0):
- Alamofire (~> 5.0)
- ObjectMapper (4.4.2)
- "OpenIMSDK (3.8.3+hotfix.3.1)":
- MJExtension
- "OpenIMSDK/Callbacker (= 3.8.3+hotfix.3.1)"
- "OpenIMSDK/CallbackProxy (= 3.8.3+hotfix.3.1)"
- "OpenIMSDK/Interface (= 3.8.3+hotfix.3.1)"
- "OpenIMSDK/Model (= 3.8.3+hotfix.3.1)"
- "OpenIMSDK/Utils (= 3.8.3+hotfix.3.1)"
- "OpenIMSDKCore (= 3.8.3+3)"
- "OpenIMSDK/Callbacker (3.8.3+hotfix.3.1)":
- MJExtension
- OpenIMSDK/Model
- OpenIMSDK/Utils
- "OpenIMSDKCore (= 3.8.3+3)"
- "OpenIMSDK/CallbackProxy (3.8.3+hotfix.3.1)":
- MJExtension
- OpenIMSDK/Utils
- "OpenIMSDKCore (= 3.8.3+3)"
- "OpenIMSDK/Interface (3.8.3+hotfix.3.1)":
- MJExtension
- OpenIMSDK/Callbacker
- OpenIMSDK/CallbackProxy
- OpenIMSDK/Model
- "OpenIMSDKCore (= 3.8.3+3)"
- "OpenIMSDK/Model (3.8.3+hotfix.3.1)":
- MJExtension
- OpenIMSDK/Utils
- "OpenIMSDKCore (= 3.8.3+3)"
- "OpenIMSDK/Utils (3.8.3+hotfix.3.1)":
- MJExtension
- "OpenIMSDKCore (= 3.8.3+3)"
- "OpenIMSDKCore (3.8.3+3)"
- Popover (1.3.0)
- RxCocoa (6.8.0):
- RxRelay (= 6.8.0)
@ -138,6 +170,7 @@ DEPENDENCIES:
- MJRefresh
- Moya
- ObjectMapper
- OpenIMSDK
- Popover
- RxCocoa
- RxDataSources
@ -179,9 +212,12 @@ SPEC REPOS:
- lottie-ios
- MarqueeLabel
- Masonry
- MJExtension
- MJRefresh
- Moya
- ObjectMapper
- OpenIMSDK
- OpenIMSDKCore
- Popover
- RxCocoa
- RxDataSources
@ -235,9 +271,12 @@ SPEC CHECKSUMS:
MarqueeLabel: 0c57d4c6634e04a6d015af79f7c9a175b2309525
Masonry: 678fab65091a9290e40e2832a55e7ab731aad201
MBProgressHUD: 1b0fb447e80a0fda94808180750e8b78a07b3cd2
MJExtension: e97d164cb411aa9795cf576093a1fa208b4a8dd8
MJRefresh: ff9e531227924c84ce459338414550a05d2aea78
Moya: 138f0573e53411fb3dc17016add0b748dfbd78ee
ObjectMapper: e6e4d91ff7f2861df7aecc536c92d8363f4c9677
OpenIMSDK: c1880296ead605bcac2a289ad0aef9170fe6e6df
OpenIMSDKCore: 75caba22be8ee484011f367711178312bd64a17d
Popover: 10e1d9528f81d9504df984b7b3f491292bc1822d
RxCocoa: 2d33c1e1e5d66492052ad46b11024ae287572880
RxDataSources: aa47cc1ed6c500fa0dfecac5c979b723542d79cf
@ -256,6 +295,6 @@ SPEC CHECKSUMS:
URLNavigator: e9c0426ba6e6ac57f34d018bbf3df840797f984d
ZXSDK: 786338c0a18e98e03eda00699c3bfd2700b97117
PODFILE CHECKSUM: 7d3667576e8d6c3f1a98be0e406f215041cf2eb7
PODFILE CHECKSUM: d9389fd0d3da8895e9ddac8adbec655edaf9bb3d
COCOAPODS: 1.16.2

19
Pods/MJExtension/LICENSE generated Normal file
View File

@ -0,0 +1,19 @@
Copyright (c) 2013-2019 MJExtension (https://github.com/CoderMJLee/MJExtension)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -0,0 +1,27 @@
//
// MJExtension.h
// MJExtension
//
// Created by mj on 14-1-15.
// Copyright (c) 2014年 小码哥. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "NSObject+MJCoding.h"
#import "NSObject+MJProperty.h"
#import "NSObject+MJClass.h"
#import "NSObject+MJKeyValue.h"
#import "NSString+MJExtension.h"
#import "MJExtensionConst.h"
#import "MJFoundation.h"
//! Project version number for MJExtension.
FOUNDATION_EXPORT double MJExtensionVersionNumber;
//! Project version string for MJExtension.
FOUNDATION_EXPORT const unsigned char MJExtensionVersionString[];
// In this header, you should import all the public headers of your framework using statements like #import <MJExtension/PublicHeader.h>

View File

@ -0,0 +1,111 @@
#ifndef __MJExtensionConst__H__
#define __MJExtensionConst__H__
#import <Foundation/Foundation.h>
#ifndef MJ_LOCK
#define MJ_LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
#endif
#ifndef MJ_UNLOCK
#define MJ_UNLOCK(lock) dispatch_semaphore_signal(lock);
#endif
// 信号量
#define MJExtensionSemaphoreCreate \
extern dispatch_semaphore_t mje_signalSemaphore; \
extern dispatch_once_t mje_onceTokenSemaphore; \
dispatch_once(&mje_onceTokenSemaphore, ^{ \
mje_signalSemaphore = dispatch_semaphore_create(1); \
});
// 过期
#define MJExtensionDeprecated(instead) NS_DEPRECATED(2_0, 2_0, 2_0, 2_0, instead)
// 构建错误
#define MJExtensionBuildError(clazz, msg) \
NSError *error = [NSError errorWithDomain:msg code:250 userInfo:nil]; \
[clazz setMj_error:error];
// 日志输出
#ifdef DEBUG
#define MJExtensionLog(...) NSLog(__VA_ARGS__)
#else
#define MJExtensionLog(...)
#endif
/**
*
* @param condition
* @param returnValue
*/
#define MJExtensionAssertError(condition, returnValue, clazz, msg) \
[clazz setMj_error:nil]; \
if ((condition) == NO) { \
MJExtensionBuildError(clazz, msg); \
return returnValue;\
}
#define MJExtensionAssert2(condition, returnValue) \
if ((condition) == NO) return returnValue;
/**
*
* @param condition
*/
#define MJExtensionAssert(condition) MJExtensionAssert2(condition, )
/**
*
* @param param
* @param returnValue
*/
#define MJExtensionAssertParamNotNil2(param, returnValue) \
MJExtensionAssert2((param) != nil, returnValue)
/**
*
* @param param
*/
#define MJExtensionAssertParamNotNil(param) MJExtensionAssertParamNotNil2(param, )
/**
*
*/
#define MJLogAllIvars \
- (NSString *)description \
{ \
return [self mj_keyValues].description; \
}
#define MJExtensionLogAllProperties MJLogAllIvars
/** 仅在 Debugger 展示所有的属性 */
#define MJImplementDebugDescription \
- (NSString *)debugDescription \
{ \
return [self mj_keyValues].debugDescription; \
}
/**
*
*/
FOUNDATION_EXPORT NSString *const MJPropertyTypeInt;
FOUNDATION_EXPORT NSString *const MJPropertyTypeShort;
FOUNDATION_EXPORT NSString *const MJPropertyTypeFloat;
FOUNDATION_EXPORT NSString *const MJPropertyTypeDouble;
FOUNDATION_EXPORT NSString *const MJPropertyTypeLong;
FOUNDATION_EXPORT NSString *const MJPropertyTypeLongLong;
FOUNDATION_EXPORT NSString *const MJPropertyTypeChar;
FOUNDATION_EXPORT NSString *const MJPropertyTypeBOOL1;
FOUNDATION_EXPORT NSString *const MJPropertyTypeBOOL2;
FOUNDATION_EXPORT NSString *const MJPropertyTypePointer;
FOUNDATION_EXPORT NSString *const MJPropertyTypeIvar;
FOUNDATION_EXPORT NSString *const MJPropertyTypeMethod;
FOUNDATION_EXPORT NSString *const MJPropertyTypeBlock;
FOUNDATION_EXPORT NSString *const MJPropertyTypeClass;
FOUNDATION_EXPORT NSString *const MJPropertyTypeSEL;
FOUNDATION_EXPORT NSString *const MJPropertyTypeId;
#endif

View File

@ -0,0 +1,27 @@
#ifndef __MJExtensionConst__M__
#define __MJExtensionConst__M__
#import <Foundation/Foundation.h>
/**
*
*/
NSString *const MJPropertyTypeInt = @"i";
NSString *const MJPropertyTypeShort = @"s";
NSString *const MJPropertyTypeFloat = @"f";
NSString *const MJPropertyTypeDouble = @"d";
NSString *const MJPropertyTypeLong = @"l";
NSString *const MJPropertyTypeLongLong = @"q";
NSString *const MJPropertyTypeChar = @"c";
NSString *const MJPropertyTypeBOOL1 = @"c";
NSString *const MJPropertyTypeBOOL2 = @"b";
NSString *const MJPropertyTypePointer = @"*";
NSString *const MJPropertyTypeIvar = @"^{objc_ivar=}";
NSString *const MJPropertyTypeMethod = @"^{objc_method=}";
NSString *const MJPropertyTypeBlock = @"@?";
NSString *const MJPropertyTypeClass = @"#";
NSString *const MJPropertyTypeSEL = @":";
NSString *const MJPropertyTypeId = @"@";
#endif

View File

@ -0,0 +1,16 @@
//
// MJFoundation.h
// MJExtensionExample
//
// Created by MJ Lee on 14/7/16.
// Copyright (c) 2014年 小码哥. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface MJFoundation : NSObject
+ (BOOL)isClassFromFoundation:(Class)c;
+ (BOOL)isFromNSObjectProtocolProperty:(NSString *)propertyName;
@end

View File

@ -0,0 +1,70 @@
//
// MJFoundation.m
// MJExtensionExample
//
// Created by MJ Lee on 14/7/16.
// Copyright (c) 2014 . All rights reserved.
//
#import "MJFoundation.h"
#import "MJExtensionConst.h"
#import <CoreData/CoreData.h>
#import "objc/runtime.h"
@implementation MJFoundation
+ (BOOL)isClassFromFoundation:(Class)c
{
if (c == [NSObject class] || c == [NSManagedObject class]) return YES;
static NSSet *foundationClasses;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// NSObjectNSObjectNSObject
foundationClasses = [NSSet setWithObjects:
[NSURL class],
[NSDate class],
[NSValue class],
[NSData class],
[NSError class],
[NSArray class],
[NSDictionary class],
[NSString class],
[NSAttributedString class], nil];
});
__block BOOL result = NO;
[foundationClasses enumerateObjectsUsingBlock:^(Class foundationClass, BOOL *stop) {
if ([c isSubclassOfClass:foundationClass]) {
result = YES;
*stop = YES;
}
}];
return result;
}
+ (BOOL)isFromNSObjectProtocolProperty:(NSString *)propertyName
{
if (!propertyName) return NO;
static NSSet<NSString *> *objectProtocolPropertyNames;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
unsigned int count = 0;
objc_property_t *propertyList = protocol_copyPropertyList(@protocol(NSObject), &count);
NSMutableSet *propertyNames = [NSMutableSet setWithCapacity:count];
for (int i = 0; i < count; i++) {
objc_property_t property = propertyList[i];
NSString *propertyName = [NSString stringWithCString:property_getName(property) encoding:NSUTF8StringEncoding];
if (propertyName) {
[propertyNames addObject:propertyName];
}
}
objectProtocolPropertyNames = [propertyNames copy];
free(propertyList);
});
return [objectProtocolPropertyNames containsObject:propertyName];
}
@end

View File

@ -0,0 +1,53 @@
//
// MJProperty.h
// MJExtensionExample
//
// Created by MJ Lee on 15/4/17.
// Copyright (c) 2015年 小码哥. All rights reserved.
// 包装一个成员属性
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#import "MJPropertyType.h"
#import "MJPropertyKey.h"
/**
*
*/
@interface MJProperty : NSObject
/** 成员属性 */
@property (nonatomic, assign) objc_property_t property;
/** 成员属性的名字 */
@property (nonatomic, readonly) NSString *name;
/** 成员属性的类型 */
@property (nonatomic, readonly) MJPropertyType *type;
/** 成员属性来源于哪个类(可能是父类) */
@property (nonatomic, assign) Class srcClass;
/**** 同一个成员属性 - 父类和子类的行为可能不一致originKey、propertyKeys、objectClassInArray ****/
/** 设置最原始的key */
- (void)setOriginKey:(id)originKey forClass:(Class)c;
/** 对应着字典中的多级key里面存放的数组数组里面都是MJPropertyKey对象 */
- (NSArray *)propertyKeysForClass:(Class)c;
/** 模型数组中的模型类型 */
- (void)setObjectClassInArray:(Class)objectClass forClass:(Class)c;
- (Class)objectClassInArrayForClass:(Class)c;
/**** 同一个成员变量 - 父类和子类的行为可能不一致key、keys、objectClassInArray ****/
/**
* object的成员变量值
*/
- (void)setValue:(id)value forObject:(id)object;
/**
* object的成员属性值
*/
- (id)valueForObject:(id)object;
/**
*
*/
+ (instancetype)cachedPropertyWithProperty:(objc_property_t)property;
@end

211
Pods/MJExtension/MJExtension/MJProperty.m generated Normal file
View File

@ -0,0 +1,211 @@
//
// MJProperty.m
// MJExtensionExample
//
// Created by MJ Lee on 15/4/17.
// Copyright (c) 2015 . All rights reserved.
//
#import "MJProperty.h"
#import "MJFoundation.h"
#import "MJExtensionConst.h"
#import <objc/message.h>
#include "TargetConditionals.h"
@interface MJProperty()
@property (strong, nonatomic) NSMutableDictionary *propertyKeysDict;
@property (strong, nonatomic) NSMutableDictionary *objectClassInArrayDict;
@property (strong, nonatomic) dispatch_semaphore_t propertyKeysLock;
@property (strong, nonatomic) dispatch_semaphore_t objectClassInArrayLock;
@end
@implementation MJProperty
#pragma mark -
- (instancetype)init
{
if (self = [super init]) {
_propertyKeysDict = [NSMutableDictionary dictionary];
_objectClassInArrayDict = [NSMutableDictionary dictionary];
_propertyKeysLock = dispatch_semaphore_create(1);
_objectClassInArrayLock = dispatch_semaphore_create(1);
}
return self;
}
#pragma mark -
+ (instancetype)cachedPropertyWithProperty:(objc_property_t)property
{
MJProperty *propertyObj = objc_getAssociatedObject(self, property);
if (propertyObj == nil) {
propertyObj = [[self alloc] init];
propertyObj.property = property;
objc_setAssociatedObject(self, property, propertyObj, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
return propertyObj;
}
#pragma mark -
- (void)setProperty:(objc_property_t)property
{
_property = property;
MJExtensionAssertParamNotNil(property);
// 1.
_name = @(property_getName(property));
// 2.
NSString *attrs = @(property_getAttributes(property));
NSUInteger dotLoc = [attrs rangeOfString:@","].location;
NSString *code = nil;
NSUInteger loc = 1;
if (dotLoc == NSNotFound) { // ,
code = [attrs substringFromIndex:loc];
} else {
code = [attrs substringWithRange:NSMakeRange(loc, dotLoc - loc)];
}
_type = [MJPropertyType cachedTypeWithCode:code];
}
/**
*
*/
- (id)valueForObject:(id)object
{
if (self.type.KVCDisabled) return [NSNull null];
id value = [object valueForKey:self.name];
// 32BOOLjsonInt
/** https://github.com/CoderMJLee/MJExtension/issues/545 */
// 32 bit device OR 32 bit Simulator
#if defined(__arm__) || (TARGET_OS_SIMULATOR && !__LP64__)
if (self.type.isBoolType) {
value = @([(NSNumber *)value boolValue]);
}
#endif
return value;
}
/**
*
*/
- (void)setValue:(id)value forObject:(id)object
{
if (self.type.KVCDisabled || value == nil) return;
[object setValue:value forKey:self.name];
}
/**
* keykeys
*/
- (NSArray *)propertyKeysWithStringKey:(NSString *)stringKey
{
if (stringKey.length == 0) return nil;
NSMutableArray *propertyKeys = [NSMutableArray array];
//
NSArray *oldKeys = [stringKey componentsSeparatedByString:@"."];
for (NSString *oldKey in oldKeys) {
NSUInteger start = [oldKey rangeOfString:@"["].location;
if (start != NSNotFound) { // key
NSString *prefixKey = [oldKey substringToIndex:start];
NSString *indexKey = prefixKey;
if (prefixKey.length) {
MJPropertyKey *propertyKey = [[MJPropertyKey alloc] init];
propertyKey.name = prefixKey;
[propertyKeys addObject:propertyKey];
indexKey = [oldKey stringByReplacingOccurrencesOfString:prefixKey withString:@""];
}
/** **/
//
NSArray *cmps = [[indexKey stringByReplacingOccurrencesOfString:@"[" withString:@""] componentsSeparatedByString:@"]"];
for (NSInteger i = 0; i<cmps.count - 1; i++) {
MJPropertyKey *subPropertyKey = [[MJPropertyKey alloc] init];
subPropertyKey.type = MJPropertyKeyTypeArray;
subPropertyKey.name = cmps[i];
[propertyKeys addObject:subPropertyKey];
}
} else { // key
MJPropertyKey *propertyKey = [[MJPropertyKey alloc] init];
propertyKey.name = oldKey;
[propertyKeys addObject:propertyKey];
}
}
return propertyKeys;
}
/** key */
- (void)setOriginKey:(id)originKey forClass:(Class)c
{
if ([originKey isKindOfClass:[NSString class]]) { // key
NSArray *propertyKeys = [self propertyKeysWithStringKey:originKey];
if (propertyKeys.count) {
[self setPropertyKeys:@[propertyKeys] forClass:c];
}
} else if ([originKey isKindOfClass:[NSArray class]]) {
NSMutableArray *keyses = [NSMutableArray array];
for (NSString *stringKey in originKey) {
NSArray *propertyKeys = [self propertyKeysWithStringKey:stringKey];
if (propertyKeys.count) {
[keyses addObject:propertyKeys];
}
}
if (keyses.count) {
[self setPropertyKeys:keyses forClass:c];
}
}
}
/** key */
- (void)setPropertyKeys:(NSArray *)propertyKeys forClass:(Class)c
{
if (propertyKeys.count == 0) return;
NSString *key = NSStringFromClass(c);
if (!key) return;
MJ_LOCK(self.propertyKeysLock);
self.propertyKeysDict[key] = propertyKeys;
MJ_UNLOCK(self.propertyKeysLock);
}
- (NSArray *)propertyKeysForClass:(Class)c
{
NSString *key = NSStringFromClass(c);
if (!key) return nil;
MJ_LOCK(self.propertyKeysLock);
NSArray *propertyKeys = self.propertyKeysDict[key];
MJ_UNLOCK(self.propertyKeysLock);
return propertyKeys;
}
/** */
- (void)setObjectClassInArray:(Class)objectClass forClass:(Class)c
{
if (!objectClass) return;
NSString *key = NSStringFromClass(c);
if (!key) return;
MJ_LOCK(self.objectClassInArrayLock);
self.objectClassInArrayDict[key] = objectClass;
MJ_UNLOCK(self.objectClassInArrayLock);
}
- (Class)objectClassInArrayForClass:(Class)c
{
NSString *key = NSStringFromClass(c);
if (!key) return nil;
MJ_LOCK(self.objectClassInArrayLock);
Class objectClass = self.objectClassInArrayDict[key];
MJ_UNLOCK(self.objectClassInArrayLock);
return objectClass;
}
@end

View File

@ -0,0 +1,30 @@
//
// MJPropertyKey.h
// MJExtensionExample
//
// Created by MJ Lee on 15/8/11.
// Copyright (c) 2015年 小码哥. All rights reserved.
//
#import <Foundation/Foundation.h>
typedef enum {
MJPropertyKeyTypeDictionary = 0, // 字典的key
MJPropertyKeyTypeArray // 数组的key
} MJPropertyKeyType;
/**
* key
*/
@interface MJPropertyKey : NSObject
/** key的名字 */
@property (copy, nonatomic) NSString *name;
/** key的种类可能是@"10",可能是@"age" */
@property (assign, nonatomic) MJPropertyKeyType type;
/**
* keynameobject
*/
- (id)valueInObject:(id)object;
@end

View File

@ -0,0 +1,25 @@
//
// MJPropertyKey.m
// MJExtensionExample
//
// Created by MJ Lee on 15/8/11.
// Copyright (c) 2015 . All rights reserved.
//
#import "MJPropertyKey.h"
@implementation MJPropertyKey
- (id)valueInObject:(id)object
{
if ([object isKindOfClass:[NSDictionary class]] && self.type == MJPropertyKeyTypeDictionary) {
return object[self.name];
} else if ([object isKindOfClass:[NSArray class]] && self.type == MJPropertyKeyTypeArray) {
NSArray *array = object;
NSUInteger index = self.name.intValue;
if (index < array.count) return array[index];
return nil;
}
return nil;
}
@end

39
Pods/MJExtension/MJExtension/MJPropertyType.h generated Executable file
View File

@ -0,0 +1,39 @@
//
// MJPropertyType.h
// MJExtension
//
// Created by mj on 14-1-15.
// Copyright (c) 2014年 小码哥. All rights reserved.
// 包装一种类型
#import <Foundation/Foundation.h>
/**
*
*/
@interface MJPropertyType : NSObject
/** 类型标识符 */
@property (nonatomic, copy) NSString *code;
/** 是否为id类型 */
@property (nonatomic, readonly, getter=isIdType) BOOL idType;
/** 是否为基本数字类型int、float等 */
@property (nonatomic, readonly, getter=isNumberType) BOOL numberType;
/** 是否为BOOL类型 */
@property (nonatomic, readonly, getter=isBoolType) BOOL boolType;
/** 对象类型如果是基本数据类型此值为nil */
@property (nonatomic, readonly) Class typeClass;
/** 类型是否来自于Foundation框架比如NSString、NSArray */
@property (nonatomic, readonly, getter = isFromFoundation) BOOL fromFoundation;
/** 类型是否不支持KVC */
@property (nonatomic, readonly, getter = isKVCDisabled) BOOL KVCDisabled;
/**
*
*/
+ (instancetype)cachedTypeWithCode:(NSString *)code;
@end

71
Pods/MJExtension/MJExtension/MJPropertyType.m generated Executable file
View File

@ -0,0 +1,71 @@
//
// MJPropertyType.m
// MJExtension
//
// Created by mj on 14-1-15.
// Copyright (c) 2014 . All rights reserved.
//
#import "MJPropertyType.h"
#import "MJExtension.h"
#import "MJFoundation.h"
#import "MJExtensionConst.h"
@implementation MJPropertyType
+ (instancetype)cachedTypeWithCode:(NSString *)code
{
MJExtensionAssertParamNotNil2(code, nil);
static NSMutableDictionary *types;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
types = [NSMutableDictionary dictionary];
});
MJPropertyType *type = types[code];
if (type == nil) {
type = [[self alloc] init];
type.code = code;
types[code] = type;
}
return type;
}
#pragma mark -
- (void)setCode:(NSString *)code
{
_code = code;
MJExtensionAssertParamNotNil(code);
if ([code isEqualToString:MJPropertyTypeId]) {
_idType = YES;
} else if (code.length == 0) {
_KVCDisabled = YES;
} else if (code.length > 3 && [code hasPrefix:@"@\""]) {
// @"和"
_code = [code substringWithRange:NSMakeRange(2, code.length - 3)];
_typeClass = NSClassFromString(_code);
_fromFoundation = [MJFoundation isClassFromFoundation:_typeClass];
_numberType = [_typeClass isSubclassOfClass:[NSNumber class]];
} else if ([code isEqualToString:MJPropertyTypeSEL] ||
[code isEqualToString:MJPropertyTypeIvar] ||
[code isEqualToString:MJPropertyTypeMethod]) {
_KVCDisabled = YES;
}
//
NSString *lowerCode = _code.lowercaseString;
NSArray *numberTypes = @[MJPropertyTypeInt, MJPropertyTypeShort, MJPropertyTypeBOOL1, MJPropertyTypeBOOL2, MJPropertyTypeFloat, MJPropertyTypeDouble, MJPropertyTypeLong, MJPropertyTypeLongLong, MJPropertyTypeChar];
if ([numberTypes containsObject:lowerCode]) {
_numberType = YES;
if ([lowerCode isEqualToString:MJPropertyTypeBOOL1]
|| [lowerCode isEqualToString:MJPropertyTypeBOOL2]) {
_boolType = YES;
}
}
}
@end

View File

@ -0,0 +1,90 @@
//
// NSObject+MJClass.h
// MJExtensionExample
//
// Created by MJ Lee on 15/8/11.
// Copyright (c) 2015年 小码哥. All rights reserved.
//
#import <Foundation/Foundation.h>
/**
* block
*/
typedef void (^MJClassesEnumeration)(Class c, BOOL *stop);
/** 这个数组中的属性名才会进行字典和模型的转换 */
typedef NSArray * (^MJAllowedPropertyNames)(void);
/** 这个数组中的属性名才会进行归档 */
typedef NSArray * (^MJAllowedCodingPropertyNames)(void);
/** 这个数组中的属性名将会被忽略:不进行字典和模型的转换 */
typedef NSArray * (^MJIgnoredPropertyNames)(void);
/** 这个数组中的属性名将会被忽略:不进行归档 */
typedef NSArray * (^MJIgnoredCodingPropertyNames)(void);
/**
*
*/
@interface NSObject (MJClass)
/**
*
*/
+ (void)mj_enumerateClasses:(MJClassesEnumeration)enumeration;
+ (void)mj_enumerateAllClasses:(MJClassesEnumeration)enumeration;
#pragma mark - 属性白名单配置
/**
*
*
* @param allowedPropertyNames
*/
+ (void)mj_setupAllowedPropertyNames:(MJAllowedPropertyNames)allowedPropertyNames;
/**
*
*/
+ (NSMutableArray *)mj_totalAllowedPropertyNames;
#pragma mark - 属性黑名单配置
/**
*
*
* @param ignoredPropertyNames
*/
+ (void)mj_setupIgnoredPropertyNames:(MJIgnoredPropertyNames)ignoredPropertyNames;
/**
*
*/
+ (NSMutableArray *)mj_totalIgnoredPropertyNames;
#pragma mark - 归档属性白名单配置
/**
*
*
* @param allowedCodingPropertyNames
*/
+ (void)mj_setupAllowedCodingPropertyNames:(MJAllowedCodingPropertyNames)allowedCodingPropertyNames;
/**
*
*/
+ (NSMutableArray *)mj_totalAllowedCodingPropertyNames;
#pragma mark - 归档属性黑名单配置
/**
*
*
* @param ignoredCodingPropertyNames
*/
+ (void)mj_setupIgnoredCodingPropertyNames:(MJIgnoredCodingPropertyNames)ignoredCodingPropertyNames;
/**
*
*/
+ (NSMutableArray *)mj_totalIgnoredCodingPropertyNames;
#pragma mark - 内部使用
+ (void)mj_setupBlockReturnValue:(id (^)(void))block key:(const char *)key;
@end

View File

@ -0,0 +1,174 @@
//
// NSObject+MJClass.m
// MJExtensionExample
//
// Created by MJ Lee on 15/8/11.
// Copyright (c) 2015 . All rights reserved.
//
#import "NSObject+MJClass.h"
#import "NSObject+MJCoding.h"
#import "NSObject+MJKeyValue.h"
#import "MJFoundation.h"
#import <objc/runtime.h>
static const char MJAllowedPropertyNamesKey = '\0';
static const char MJIgnoredPropertyNamesKey = '\0';
static const char MJAllowedCodingPropertyNamesKey = '\0';
static const char MJIgnoredCodingPropertyNamesKey = '\0';
@implementation NSObject (MJClass)
+ (NSMutableDictionary *)mj_classDictForKey:(const void *)key
{
static NSMutableDictionary *allowedPropertyNamesDict;
static NSMutableDictionary *ignoredPropertyNamesDict;
static NSMutableDictionary *allowedCodingPropertyNamesDict;
static NSMutableDictionary *ignoredCodingPropertyNamesDict;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
allowedPropertyNamesDict = [NSMutableDictionary dictionary];
ignoredPropertyNamesDict = [NSMutableDictionary dictionary];
allowedCodingPropertyNamesDict = [NSMutableDictionary dictionary];
ignoredCodingPropertyNamesDict = [NSMutableDictionary dictionary];
});
if (key == &MJAllowedPropertyNamesKey) return allowedPropertyNamesDict;
if (key == &MJIgnoredPropertyNamesKey) return ignoredPropertyNamesDict;
if (key == &MJAllowedCodingPropertyNamesKey) return allowedCodingPropertyNamesDict;
if (key == &MJIgnoredCodingPropertyNamesKey) return ignoredCodingPropertyNamesDict;
return nil;
}
+ (void)mj_enumerateClasses:(MJClassesEnumeration)enumeration
{
// 1.block
if (enumeration == nil) return;
// 2.
BOOL stop = NO;
// 3.
Class c = self;
// 4.
while (c && !stop) {
// 4.1.
enumeration(c, &stop);
// 4.2.
c = class_getSuperclass(c);
if ([MJFoundation isClassFromFoundation:c]) break;
}
}
+ (void)mj_enumerateAllClasses:(MJClassesEnumeration)enumeration
{
// 1.block
if (enumeration == nil) return;
// 2.
BOOL stop = NO;
// 3.
Class c = self;
// 4.
while (c && !stop) {
// 4.1.
enumeration(c, &stop);
// 4.2.
c = class_getSuperclass(c);
}
}
#pragma mark -
+ (void)mj_setupIgnoredPropertyNames:(MJIgnoredPropertyNames)ignoredPropertyNames
{
[self mj_setupBlockReturnValue:ignoredPropertyNames key:&MJIgnoredPropertyNamesKey];
}
+ (NSMutableArray *)mj_totalIgnoredPropertyNames
{
return [self mj_totalObjectsWithSelector:@selector(mj_ignoredPropertyNames) key:&MJIgnoredPropertyNamesKey];
}
#pragma mark -
+ (void)mj_setupIgnoredCodingPropertyNames:(MJIgnoredCodingPropertyNames)ignoredCodingPropertyNames
{
[self mj_setupBlockReturnValue:ignoredCodingPropertyNames key:&MJIgnoredCodingPropertyNamesKey];
}
+ (NSMutableArray *)mj_totalIgnoredCodingPropertyNames
{
return [self mj_totalObjectsWithSelector:@selector(mj_ignoredCodingPropertyNames) key:&MJIgnoredCodingPropertyNamesKey];
}
#pragma mark -
+ (void)mj_setupAllowedPropertyNames:(MJAllowedPropertyNames)allowedPropertyNames;
{
[self mj_setupBlockReturnValue:allowedPropertyNames key:&MJAllowedPropertyNamesKey];
}
+ (NSMutableArray *)mj_totalAllowedPropertyNames
{
return [self mj_totalObjectsWithSelector:@selector(mj_allowedPropertyNames) key:&MJAllowedPropertyNamesKey];
}
#pragma mark -
+ (void)mj_setupAllowedCodingPropertyNames:(MJAllowedCodingPropertyNames)allowedCodingPropertyNames
{
[self mj_setupBlockReturnValue:allowedCodingPropertyNames key:&MJAllowedCodingPropertyNamesKey];
}
+ (NSMutableArray *)mj_totalAllowedCodingPropertyNames
{
return [self mj_totalObjectsWithSelector:@selector(mj_allowedCodingPropertyNames) key:&MJAllowedCodingPropertyNamesKey];
}
#pragma mark - block:block
+ (void)mj_setupBlockReturnValue:(id (^)(void))block key:(const char *)key {
MJExtensionSemaphoreCreate
MJ_LOCK(mje_signalSemaphore);
if (block) {
objc_setAssociatedObject(self, key, block(), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
} else {
objc_setAssociatedObject(self, key, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
//
[[self mj_classDictForKey:key] removeAllObjects];
MJ_UNLOCK(mje_signalSemaphore);
}
+ (NSMutableArray *)mj_totalObjectsWithSelector:(SEL)selector key:(const char *)key
{
MJExtensionSemaphoreCreate
MJ_LOCK(mje_signalSemaphore);
NSMutableArray *array = [self mj_classDictForKey:key][NSStringFromClass(self)];
if (array == nil) {
//
[self mj_classDictForKey:key][NSStringFromClass(self)] = array = [NSMutableArray array];
if ([self respondsToSelector:selector]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
NSArray *subArray = [self performSelector:selector];
#pragma clang diagnostic pop
if (subArray) {
[array addObjectsFromArray:subArray];
}
}
[self mj_enumerateAllClasses:^(__unsafe_unretained Class c, BOOL *stop) {
NSArray *subArray = objc_getAssociatedObject(c, key);
[array addObjectsFromArray:subArray];
}];
}
MJ_UNLOCK(mje_signalSemaphore);
return array;
}
@end

View File

@ -0,0 +1,66 @@
//
// NSObject+MJCoding.h
// MJExtension
//
// Created by mj on 14-1-15.
// Copyright (c) 2014年 小码哥. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "MJExtensionConst.h"
/**
* Codeing协议
*/
@protocol MJCoding <NSObject>
@optional
/**
*
*/
+ (NSArray *)mj_allowedCodingPropertyNames;
/**
*
*/
+ (NSArray *)mj_ignoredCodingPropertyNames;
@end
@interface NSObject (MJCoding) <MJCoding>
/**
*
*/
- (void)mj_decode:(NSCoder *)decoder;
/**
*
*/
- (void)mj_encode:(NSCoder *)encoder;
@end
/**
*/
#define MJCodingImplementation \
- (id)initWithCoder:(NSCoder *)decoder \
{ \
if (self = [super init]) { \
[self mj_decode:decoder]; \
} \
return self; \
} \
\
- (void)encodeWithCoder:(NSCoder *)encoder \
{ \
[self mj_encode:encoder]; \
}\
#define MJExtensionCodingImplementation MJCodingImplementation
#define MJSecureCodingImplementation(CLASS, FLAG) \
@interface CLASS (MJSecureCoding) <NSSecureCoding> \
@end \
@implementation CLASS (MJSecureCoding) \
MJCodingImplementation \
+ (BOOL)supportsSecureCoding { \
return FLAG; \
} \
@end \

View File

@ -0,0 +1,59 @@
//
// NSObject+MJCoding.m
// MJExtension
//
// Created by mj on 14-1-15.
// Copyright (c) 2014 . All rights reserved.
//
#import "NSObject+MJCoding.h"
#import "NSObject+MJClass.h"
#import "NSObject+MJProperty.h"
#import "MJProperty.h"
@implementation NSObject (MJCoding)
- (void)mj_encode:(NSCoder *)encoder
{
Class clazz = [self class];
NSArray *allowedCodingPropertyNames = [clazz mj_totalAllowedCodingPropertyNames];
NSArray *ignoredCodingPropertyNames = [clazz mj_totalIgnoredCodingPropertyNames];
[clazz mj_enumerateProperties:^(MJProperty *property, BOOL *stop) {
//
if (allowedCodingPropertyNames.count && ![allowedCodingPropertyNames containsObject:property.name]) return;
if ([ignoredCodingPropertyNames containsObject:property.name]) return;
id value = [property valueForObject:self];
if (value == nil) return;
[encoder encodeObject:value forKey:property.name];
}];
}
- (void)mj_decode:(NSCoder *)decoder
{
Class clazz = [self class];
NSArray *allowedCodingPropertyNames = [clazz mj_totalAllowedCodingPropertyNames];
NSArray *ignoredCodingPropertyNames = [clazz mj_totalIgnoredCodingPropertyNames];
[clazz mj_enumerateProperties:^(MJProperty *property, BOOL *stop) {
//
if (allowedCodingPropertyNames.count && ![allowedCodingPropertyNames containsObject:property.name]) return;
if ([ignoredCodingPropertyNames containsObject:property.name]) return;
// fixed `-[NSKeyedUnarchiver validateAllowedClass:forKey:] allowed unarchiving safe plist type ''NSNumber'(This will be disallowed in the future.)` warning.
Class genericClass = [property objectClassInArrayForClass:property.srcClass];
// If genericClass exists, property.type.typeClass would be a collection type(Array, Set, Dictionary). This scenario([obj, nil, obj, nil]) would not happened.
NSSet *classes = [NSSet setWithObjects:NSNumber.class,
property.type.typeClass, genericClass, nil];
id value = [decoder decodeObjectOfClasses:classes forKey:property.name];
if (value == nil) { // MJExtension
value = [decoder decodeObjectForKey:[@"_" stringByAppendingString:property.name]];
}
if (value == nil) return;
[property setValue:value forObject:self];
}];
}
@end

View File

@ -0,0 +1,194 @@
//
// NSObject+MJKeyValue.h
// MJExtension
//
// Created by mj on 13-8-24.
// Copyright (c) 2013年 小码哥. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "MJExtensionConst.h"
#import <CoreData/CoreData.h>
#import "MJProperty.h"
/**
* KeyValue协议
*/
@protocol MJKeyValue <NSObject>
@optional
/**
*
*/
+ (NSArray *)mj_allowedPropertyNames;
/**
*
*/
+ (NSArray *)mj_ignoredPropertyNames;
/**
* key去字典中取值
*
* @return key是属性名value是从字典中取值用的key
*/
+ (NSDictionary *)mj_replacedKeyFromPropertyName;
/**
* key去字典中取值
*
* @return key
*/
+ (id)mj_replacedKeyFromPropertyName121:(NSString *)propertyName;
/**
*
*
* @return key是数组属性名value是数组中存放模型的ClassClass类型或者NSString类型
*/
+ (NSDictionary *)mj_objectClassInArray;
/** 特殊地区在字符串格式化数字时使用 */
+ (NSLocale *)mj_numberLocale;
/**
*
*
* @param oldValue
*
* @return
*/
- (id)mj_newValueFromOldValue:(id)oldValue property:(MJProperty *)property;
/**
*
*/
- (void)mj_keyValuesDidFinishConvertingToObject MJExtensionDeprecated("请使用`mj_didConvertToObjectWithKeyValues:`替代");
- (void)mj_keyValuesDidFinishConvertingToObject:(NSDictionary *)keyValues MJExtensionDeprecated("请使用`mj_didConvertToObjectWithKeyValues:`替代");
- (void)mj_didConvertToObjectWithKeyValues:(NSDictionary *)keyValues;
/**
*
*/
- (void)mj_objectDidFinishConvertingToKeyValues MJExtensionDeprecated("请使用`mj_objectDidConvertToKeyValues:`替代");
- (void)mj_objectDidConvertToKeyValues:(NSMutableDictionary *)keyValues;
@end
@interface NSObject (MJKeyValue) <MJKeyValue>
#pragma mark - 类方法
/**
*
*/
+ (NSError *)mj_error;
/**
* key是否参考replacedKeyFromPropertyName等方法
*/
+ (void)mj_referenceReplacedKeyWhenCreatingKeyValues:(BOOL)reference;
#pragma mark - 对象方法
/**
*
* @param keyValues (NSDictionaryNSDataNSString)
*/
- (instancetype)mj_setKeyValues:(id)keyValues;
/**
*
* @param keyValues (NSDictionaryNSDataNSString)
* @param context CoreData上下文
*/
- (instancetype)mj_setKeyValues:(id)keyValues context:(NSManagedObjectContext *)context;
/**
*
* @return
*/
- (NSMutableDictionary *)mj_keyValues;
- (NSMutableDictionary *)mj_keyValuesWithKeys:(NSArray *)keys;
- (NSMutableDictionary *)mj_keyValuesWithIgnoredKeys:(NSArray *)ignoredKeys;
/**
*
* @param objectArray
* @return
*/
+ (NSMutableArray *)mj_keyValuesArrayWithObjectArray:(NSArray *)objectArray;
+ (NSMutableArray *)mj_keyValuesArrayWithObjectArray:(NSArray *)objectArray keys:(NSArray *)keys;
+ (NSMutableArray *)mj_keyValuesArrayWithObjectArray:(NSArray *)objectArray ignoredKeys:(NSArray *)ignoredKeys;
#pragma mark - 字典转模型
/**
*
* @param keyValues (NSDictionaryNSDataNSString)
* @return
*/
+ (instancetype)mj_objectWithKeyValues:(id)keyValues;
/**
* CoreData模型
* @param keyValues (NSDictionaryNSDataNSString)
* @param context CoreData上下文
* @return
*/
+ (instancetype)mj_objectWithKeyValues:(id)keyValues context:(NSManagedObjectContext *)context;
/**
* plist来创建一个模型
* @param filename (mainBundle中的文件)
* @return
*/
+ (instancetype)mj_objectWithFilename:(NSString *)filename;
/**
* plist来创建一个模型
* @param file
* @return
*/
+ (instancetype)mj_objectWithFile:(NSString *)file;
#pragma mark - 字典数组转模型数组
/**
*
* @param keyValuesArray (NSDictionaryNSDataNSString)
* @return
*/
+ (NSMutableArray *)mj_objectArrayWithKeyValuesArray:(id)keyValuesArray;
/**
*
* @param keyValuesArray (NSDictionaryNSDataNSString)
* @param context CoreData上下文
* @return
*/
+ (NSMutableArray *)mj_objectArrayWithKeyValuesArray:(id)keyValuesArray context:(NSManagedObjectContext *)context;
/**
* plist来创建一个模型数组
* @param filename (mainBundle中的文件)
* @return
*/
+ (NSMutableArray *)mj_objectArrayWithFilename:(NSString *)filename;
/**
* plist来创建一个模型数组
* @param file
* @return
*/
+ (NSMutableArray *)mj_objectArrayWithFile:(NSString *)file;
#pragma mark - 转换为JSON
/**
* JSON Data
*/
- (NSData *)mj_JSONData;
/**
*
*/
- (id)mj_JSONObject;
/**
* JSON
*/
- (NSString *)mj_JSONString;
@end

View File

@ -0,0 +1,524 @@
//
// NSObject+MJKeyValue.m
// MJExtension
//
// Created by mj on 13-8-24.
// Copyright (c) 2013 . All rights reserved.
//
#import "NSObject+MJKeyValue.h"
#import "NSObject+MJProperty.h"
#import "NSString+MJExtension.h"
#import "MJProperty.h"
#import "MJPropertyType.h"
#import "MJExtensionConst.h"
#import "MJFoundation.h"
#import "NSString+MJExtension.h"
#import "NSObject+MJClass.h"
@implementation NSDecimalNumber(MJKeyValue)
- (id)mj_standardValueWithTypeCode:(NSString *)typeCode {
// , Long, 64 , 2 ,
// 32 , 使 Double
if ([typeCode isEqualToString:MJPropertyTypeLongLong]) {
return @(self.longLongValue);
} else if ([typeCode isEqualToString:MJPropertyTypeLongLong.uppercaseString]) {
return @(self.unsignedLongLongValue);
} else if ([typeCode isEqualToString:MJPropertyTypeLong]) {
return @(self.longValue);
} else if ([typeCode isEqualToString:MJPropertyTypeLong.uppercaseString]) {
return @(self.unsignedLongValue);
} else {
return @(self.doubleValue);
}
}
@end
@implementation NSObject (MJKeyValue)
#pragma mark -
static const char MJErrorKey = '\0';
+ (NSError *)mj_error
{
return objc_getAssociatedObject(self, &MJErrorKey);
}
+ (void)setMj_error:(NSError *)error
{
objc_setAssociatedObject(self, &MJErrorKey, error, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
#pragma mark - ->
/** keyreplacedKeyFromPropertyName */
static const char MJReferenceReplacedKeyWhenCreatingKeyValuesKey = '\0';
+ (void)mj_referenceReplacedKeyWhenCreatingKeyValues:(BOOL)reference
{
objc_setAssociatedObject(self, &MJReferenceReplacedKeyWhenCreatingKeyValuesKey, @(reference), OBJC_ASSOCIATION_ASSIGN);
}
+ (BOOL)mj_isReferenceReplacedKeyWhenCreatingKeyValues
{
__block id value = objc_getAssociatedObject(self, &MJReferenceReplacedKeyWhenCreatingKeyValuesKey);
if (!value) {
[self mj_enumerateAllClasses:^(__unsafe_unretained Class c, BOOL *stop) {
value = objc_getAssociatedObject(c, &MJReferenceReplacedKeyWhenCreatingKeyValuesKey);
if (value) *stop = YES;
}];
}
return [value boolValue];
}
#pragma mark - ----
+ (void)load
{
//
[self mj_referenceReplacedKeyWhenCreatingKeyValues:YES];
}
#pragma mark - ----
#pragma mark - ->
- (instancetype)mj_setKeyValues:(id)keyValues
{
return [self mj_setKeyValues:keyValues context:nil];
}
/**
*/
- (instancetype)mj_setKeyValues:(id)keyValues context:(NSManagedObjectContext *)context
{
// JSON
keyValues = [keyValues mj_JSONObject];
MJExtensionAssertError([keyValues isKindOfClass:[NSDictionary class]], self, [self class], @"keyValues参数不是一个字典");
Class clazz = [self class];
NSArray *allowedPropertyNames = [clazz mj_totalAllowedPropertyNames];
NSArray *ignoredPropertyNames = [clazz mj_totalIgnoredPropertyNames];
NSLocale *numberLocale = nil;
if ([self.class respondsToSelector:@selector(mj_numberLocale)]) {
numberLocale = self.class.mj_numberLocale;
}
//
[clazz mj_enumerateProperties:^(MJProperty *property, BOOL *stop) {
@try {
// 0.
if (allowedPropertyNames.count && ![allowedPropertyNames containsObject:property.name]) return;
if ([ignoredPropertyNames containsObject:property.name]) return;
// 1.
id value;
NSArray *propertyKeyses = [property propertyKeysForClass:clazz];
for (NSArray *propertyKeys in propertyKeyses) {
value = keyValues;
for (MJPropertyKey *propertyKey in propertyKeys) {
value = [propertyKey valueInObject:value];
}
if (value) break;
}
//
id newValue = [clazz mj_getNewValueFromObject:self oldValue:value property:property];
if (newValue != value) { //
[property setValue:newValue forObject:self];
return;
}
//
if (!value || value == [NSNull null]) return;
// 2.
MJPropertyType *type = property.type;
Class propertyClass = type.typeClass;
Class objectClass = [property objectClassInArrayForClass:[self class]];
// ->
if (propertyClass == [NSMutableArray class] && [value isKindOfClass:[NSArray class]]) {
value = [NSMutableArray arrayWithArray:value];
} else if (propertyClass == [NSMutableDictionary class] && [value isKindOfClass:[NSDictionary class]]) {
value = [NSMutableDictionary dictionaryWithDictionary:value];
} else if (propertyClass == [NSMutableString class] && [value isKindOfClass:[NSString class]]) {
value = [NSMutableString stringWithString:value];
} else if (propertyClass == [NSMutableData class] && [value isKindOfClass:[NSData class]]) {
value = [NSMutableData dataWithData:value];
}
if (!type.isFromFoundation && propertyClass) { //
value = [propertyClass mj_objectWithKeyValues:value context:context];
} else if (objectClass) {
if (objectClass == [NSURL class] && [value isKindOfClass:[NSArray class]]) {
// string array -> url array
NSMutableArray *urlArray = [NSMutableArray array];
for (NSString *string in value) {
if (![string isKindOfClass:[NSString class]]) continue;
[urlArray addObject:string.mj_url];
}
value = urlArray;
} else { // -->
value = [objectClass mj_objectArrayWithKeyValuesArray:value context:context];
}
} else if (propertyClass == [NSString class]) {
if ([value isKindOfClass:[NSNumber class]]) {
// NSNumber -> NSString
value = [value description];
} else if ([value isKindOfClass:[NSURL class]]) {
// NSURL -> NSString
value = [value absoluteString];
}
} else if ([value isKindOfClass:[NSString class]]) {
if (propertyClass == [NSURL class]) {
// NSString -> NSURL
//
value = [value mj_url];
} else if (type.isNumberType) {
NSString *oldValue = value;
// NSString -> NSDecimalNumber, 使 DecimalNumber ,
NSDecimalNumber *decimalValue = [NSDecimalNumber decimalNumberWithString:oldValue
locale:numberLocale];
//
if (decimalValue == NSDecimalNumber.notANumber) {
value = @(0);
}else if (propertyClass != [NSDecimalNumber class]) {
value = [decimalValue mj_standardValueWithTypeCode:type.code];
} else {
value = decimalValue;
}
// BOOL
if (type.isBoolType) {
// BOOLcharValue
// charValueBOOL
NSString *lower = [oldValue lowercaseString];
if ([lower isEqualToString:@"yes"] || [lower isEqualToString:@"true"]) {
value = @YES;
} else if ([lower isEqualToString:@"no"] || [lower isEqualToString:@"false"]) {
value = @NO;
}
}
}
} else if ([value isKindOfClass:[NSNumber class]] && propertyClass == [NSDecimalNumber class]){
// NSDecimalNumber
if (![value isKindOfClass:[NSDecimalNumber class]]) {
value = [NSDecimalNumber decimalNumberWithDecimal:[((NSNumber *)value) decimalValue]];
}
}
// , value property
if (propertyClass && ![value isKindOfClass:propertyClass]) {
value = nil;
}
// 3.
[property setValue:value forObject:self];
} @catch (NSException *exception) {
MJExtensionBuildError([self class], exception.reason);
MJExtensionLog(@"%@", exception);
#ifdef DEBUG
[exception raise];
#endif
}
}];
//
if ([self respondsToSelector:@selector(mj_didConvertToObjectWithKeyValues:)]) {
[self mj_didConvertToObjectWithKeyValues:keyValues];
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored"-Wdeprecated-declarations"
if ([self respondsToSelector:@selector(mj_keyValuesDidFinishConvertingToObject)]) {
[self mj_keyValuesDidFinishConvertingToObject];
}
if ([self respondsToSelector:@selector(mj_keyValuesDidFinishConvertingToObject:)]) {
[self mj_keyValuesDidFinishConvertingToObject:keyValues];
}
#pragma clang diagnostic pop
return self;
}
+ (instancetype)mj_objectWithKeyValues:(id)keyValues
{
return [self mj_objectWithKeyValues:keyValues context:nil];
}
+ (instancetype)mj_objectWithKeyValues:(id)keyValues context:(NSManagedObjectContext *)context
{
// JSON
keyValues = [keyValues mj_JSONObject];
MJExtensionAssertError([keyValues isKindOfClass:[NSDictionary class]], nil, [self class], @"keyValues参数不是一个字典");
if ([self isSubclassOfClass:[NSManagedObject class]] && context) {
NSString *entityName = [(NSManagedObject *)self entity].name;
return [[NSEntityDescription insertNewObjectForEntityForName:entityName inManagedObjectContext:context] mj_setKeyValues:keyValues context:context];
}
return [[[self alloc] init] mj_setKeyValues:keyValues];
}
+ (instancetype)mj_objectWithFilename:(NSString *)filename
{
MJExtensionAssertError(filename != nil, nil, [self class], @"filename参数为nil");
return [self mj_objectWithFile:[[NSBundle mainBundle] pathForResource:filename ofType:nil]];
}
+ (instancetype)mj_objectWithFile:(NSString *)file
{
MJExtensionAssertError(file != nil, nil, [self class], @"file参数为nil");
return [self mj_objectWithKeyValues:[NSDictionary dictionaryWithContentsOfFile:file]];
}
#pragma mark - ->
+ (NSMutableArray *)mj_objectArrayWithKeyValuesArray:(NSArray *)keyValuesArray
{
return [self mj_objectArrayWithKeyValuesArray:keyValuesArray context:nil];
}
+ (NSMutableArray *)mj_objectArrayWithKeyValuesArray:(id)keyValuesArray context:(NSManagedObjectContext *)context
{
// JSON
keyValuesArray = [keyValuesArray mj_JSONObject];
// 1.
MJExtensionAssertError([keyValuesArray isKindOfClass:[NSArray class]], nil, [self class], @"keyValuesArray参数不是一个数组");
// NSStringNSNumber
if ([MJFoundation isClassFromFoundation:self]) return [NSMutableArray arrayWithArray:keyValuesArray];
// 2.
NSMutableArray *modelArray = [NSMutableArray array];
// 3.
for (NSDictionary *keyValues in keyValuesArray) {
if ([keyValues isKindOfClass:[NSArray class]]){
[modelArray addObject:[self mj_objectArrayWithKeyValuesArray:keyValues context:context]];
} else {
id model = [self mj_objectWithKeyValues:keyValues context:context];
if (model) [modelArray addObject:model];
}
}
return modelArray;
}
+ (NSMutableArray *)mj_objectArrayWithFilename:(NSString *)filename
{
MJExtensionAssertError(filename != nil, nil, [self class], @"filename参数为nil");
return [self mj_objectArrayWithFile:[[NSBundle mainBundle] pathForResource:filename ofType:nil]];
}
+ (NSMutableArray *)mj_objectArrayWithFile:(NSString *)file
{
MJExtensionAssertError(file != nil, nil, [self class], @"file参数为nil");
return [self mj_objectArrayWithKeyValuesArray:[NSArray arrayWithContentsOfFile:file]];
}
#pragma mark - ->
- (NSMutableDictionary *)mj_keyValues
{
return [self mj_keyValuesWithKeys:nil ignoredKeys:nil];
}
- (NSMutableDictionary *)mj_keyValuesWithKeys:(NSArray *)keys
{
return [self mj_keyValuesWithKeys:keys ignoredKeys:nil];
}
- (NSMutableDictionary *)mj_keyValuesWithIgnoredKeys:(NSArray *)ignoredKeys
{
return [self mj_keyValuesWithKeys:nil ignoredKeys:ignoredKeys];
}
- (NSMutableDictionary *)mj_keyValuesWithKeys:(NSArray *)keys ignoredKeys:(NSArray *)ignoredKeys
{
// ,
// NSNull
//
if ([self isMemberOfClass:NSNull.class]) { return nil; }
// , .
// TODO: ,
MJExtensionAssertError(![MJFoundation isClassFromFoundation:[self class]], (NSMutableDictionary *)self, [self class], @"不是自定义的模型类")
id keyValues = [NSMutableDictionary dictionary];
Class clazz = [self class];
NSArray *allowedPropertyNames = [clazz mj_totalAllowedPropertyNames];
NSArray *ignoredPropertyNames = [clazz mj_totalIgnoredPropertyNames];
[clazz mj_enumerateProperties:^(MJProperty *property, BOOL *stop) {
@try {
// 0.
if (allowedPropertyNames.count && ![allowedPropertyNames containsObject:property.name]) return;
if ([ignoredPropertyNames containsObject:property.name]) return;
if (keys.count && ![keys containsObject:property.name]) return;
if ([ignoredKeys containsObject:property.name]) return;
// 1.
id value = [property valueForObject:self];
if (!value) return;
// 2.
MJPropertyType *type = property.type;
Class propertyClass = type.typeClass;
if (!type.isFromFoundation && propertyClass) {
value = [value mj_keyValues];
} else if ([value isKindOfClass:[NSArray class]]) {
// 3.
value = [NSObject mj_keyValuesArrayWithObjectArray:value];
} else if (propertyClass == [NSURL class]) {
value = [value absoluteString];
}
// 4.
if ([clazz mj_isReferenceReplacedKeyWhenCreatingKeyValues]) {
NSArray *propertyKeys = [[property propertyKeysForClass:clazz] firstObject];
NSUInteger keyCount = propertyKeys.count;
//
__block id innerContainer = keyValues;
[propertyKeys enumerateObjectsUsingBlock:^(MJPropertyKey *propertyKey, NSUInteger idx, BOOL *stop) {
//
MJPropertyKey *nextPropertyKey = nil;
if (idx != keyCount - 1) {
nextPropertyKey = propertyKeys[idx + 1];
}
if (nextPropertyKey) { // key
// propertyKey
id tempInnerContainer = [propertyKey valueInObject:innerContainer];
if (tempInnerContainer == nil || [tempInnerContainer isKindOfClass:[NSNull class]]) {
if (nextPropertyKey.type == MJPropertyKeyTypeDictionary) {
tempInnerContainer = [NSMutableDictionary dictionary];
} else {
tempInnerContainer = [NSMutableArray array];
}
if (propertyKey.type == MJPropertyKeyTypeDictionary) {
innerContainer[propertyKey.name] = tempInnerContainer;
} else {
innerContainer[propertyKey.name.intValue] = tempInnerContainer;
}
}
if ([tempInnerContainer isKindOfClass:[NSMutableArray class]]) {
NSMutableArray *tempInnerContainerArray = tempInnerContainer;
int index = nextPropertyKey.name.intValue;
while (tempInnerContainerArray.count < index + 1) {
[tempInnerContainerArray addObject:[NSNull null]];
}
}
innerContainer = tempInnerContainer;
} else { // key
if (propertyKey.type == MJPropertyKeyTypeDictionary) {
innerContainer[propertyKey.name] = value;
} else {
innerContainer[propertyKey.name.intValue] = value;
}
}
}];
} else {
keyValues[property.name] = value;
}
} @catch (NSException *exception) {
MJExtensionBuildError([self class], exception.reason);
MJExtensionLog(@"%@", exception);
#ifdef DEBUG
[exception raise];
#endif
}
}];
//
if ([self respondsToSelector:@selector(mj_objectDidConvertToKeyValues:)]) {
[self mj_objectDidConvertToKeyValues:keyValues];
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored"-Wdeprecated-declarations"
if ([self respondsToSelector:@selector(mj_objectDidFinishConvertingToKeyValues)]) {
[self mj_objectDidFinishConvertingToKeyValues];
}
#pragma clang diagnostic pop
return keyValues;
}
#pragma mark - ->
+ (NSMutableArray *)mj_keyValuesArrayWithObjectArray:(NSArray *)objectArray
{
return [self mj_keyValuesArrayWithObjectArray:objectArray keys:nil ignoredKeys:nil];
}
+ (NSMutableArray *)mj_keyValuesArrayWithObjectArray:(NSArray *)objectArray keys:(NSArray *)keys
{
return [self mj_keyValuesArrayWithObjectArray:objectArray keys:keys ignoredKeys:nil];
}
+ (NSMutableArray *)mj_keyValuesArrayWithObjectArray:(NSArray *)objectArray ignoredKeys:(NSArray *)ignoredKeys
{
return [self mj_keyValuesArrayWithObjectArray:objectArray keys:nil ignoredKeys:ignoredKeys];
}
+ (NSMutableArray *)mj_keyValuesArrayWithObjectArray:(NSArray *)objectArray keys:(NSArray *)keys ignoredKeys:(NSArray *)ignoredKeys
{
// 0.
MJExtensionAssertError([objectArray isKindOfClass:[NSArray class]], nil, [self class], @"objectArray参数不是一个数组");
// 1.
NSMutableArray *keyValuesArray = [NSMutableArray array];
for (id object in objectArray) {
if (keys) {
id convertedObj = [object mj_keyValuesWithKeys:keys];
if (!convertedObj) { continue; }
[keyValuesArray addObject:convertedObj];
} else {
id convertedObj = [object mj_keyValuesWithIgnoredKeys:ignoredKeys];
if (!convertedObj) { continue; }
[keyValuesArray addObject:convertedObj];
}
}
return keyValuesArray;
}
#pragma mark - JSON
- (NSData *)mj_JSONData
{
if ([self isKindOfClass:[NSString class]]) {
return [((NSString *)self) dataUsingEncoding:NSUTF8StringEncoding];
} else if ([self isKindOfClass:[NSData class]]) {
return (NSData *)self;
}
return [NSJSONSerialization dataWithJSONObject:[self mj_JSONObject] options:kNilOptions error:nil];
}
- (id)mj_JSONObject
{
if ([self isKindOfClass:[NSString class]]) {
return [NSJSONSerialization JSONObjectWithData:[((NSString *)self) dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:nil];
} else if ([self isKindOfClass:[NSData class]]) {
return [NSJSONSerialization JSONObjectWithData:(NSData *)self options:kNilOptions error:nil];
}
return self.mj_keyValues;
}
- (NSString *)mj_JSONString
{
if ([self isKindOfClass:[NSString class]]) {
return (NSString *)self;
} else if ([self isKindOfClass:[NSData class]]) {
return [[NSString alloc] initWithData:(NSData *)self encoding:NSUTF8StringEncoding];
}
return [[NSString alloc] initWithData:[self mj_JSONData] encoding:NSUTF8StringEncoding];
}
@end

View File

@ -0,0 +1,70 @@
//
// NSObject+MJProperty.h
// MJExtensionExample
//
// Created by MJ Lee on 15/4/17.
// Copyright (c) 2015年 小码哥. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "MJExtensionConst.h"
@class MJProperty;
/**
* block
*
* @param property
* @param stop YES代表停止遍历NO代表继续遍历
*/
typedef void (^MJPropertiesEnumeration)(MJProperty *property, BOOL *stop);
/** 将属性名换为其他key去字典中取值 */
typedef NSDictionary * (^MJReplacedKeyFromPropertyName)(void);
typedef id (^MJReplacedKeyFromPropertyName121)(NSString *propertyName);
/** 数组中需要转换的模型类 */
typedef NSDictionary * (^MJObjectClassInArray)(void);
/** 用于过滤字典中的值 */
typedef id (^MJNewValueFromOldValue)(id object, id oldValue, MJProperty *property);
/**
*
*/
@interface NSObject (MJProperty)
#pragma mark - 遍历
/**
*
*/
+ (void)mj_enumerateProperties:(MJPropertiesEnumeration)enumeration;
#pragma mark - 新值配置
/**
*
*
* @param newValueFormOldValue
*/
+ (void)mj_setupNewValueFromOldValue:(MJNewValueFromOldValue)newValueFormOldValue;
+ (id)mj_getNewValueFromObject:(__unsafe_unretained id)object oldValue:(__unsafe_unretained id)oldValue property:(__unsafe_unretained MJProperty *)property;
#pragma mark - key配置
/**
* key去字典中取值
*
* @param replacedKeyFromPropertyName key去字典中取值
*/
+ (void)mj_setupReplacedKeyFromPropertyName:(MJReplacedKeyFromPropertyName)replacedKeyFromPropertyName;
/**
* key去字典中取值
*
* @param replacedKeyFromPropertyName121 key去字典中取值
*/
+ (void)mj_setupReplacedKeyFromPropertyName121:(MJReplacedKeyFromPropertyName121)replacedKeyFromPropertyName121;
#pragma mark - array model class配置
/**
*
*
* @param objectClassInArray
*/
+ (void)mj_setupObjectClassInArray:(MJObjectClassInArray)objectClassInArray;
@end

View File

@ -0,0 +1,240 @@
//
// NSObject+MJProperty.m
// MJExtensionExample
//
// Created by MJ Lee on 15/4/17.
// Copyright (c) 2015 . All rights reserved.
//
#import "NSObject+MJProperty.h"
#import "NSObject+MJKeyValue.h"
#import "NSObject+MJCoding.h"
#import "NSObject+MJClass.h"
#import "MJProperty.h"
#import "MJFoundation.h"
#import <objc/runtime.h>
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundeclared-selector"
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
static const char MJReplacedKeyFromPropertyNameKey = '\0';
static const char MJReplacedKeyFromPropertyName121Key = '\0';
static const char MJNewValueFromOldValueKey = '\0';
static const char MJObjectClassInArrayKey = '\0';
static const char MJCachedPropertiesKey = '\0';
dispatch_semaphore_t mje_signalSemaphore;
dispatch_once_t mje_onceTokenSemaphore;
@implementation NSObject (Property)
+ (NSMutableDictionary *)mj_propertyDictForKey:(const void *)key
{
static NSMutableDictionary *replacedKeyFromPropertyNameDict;
static NSMutableDictionary *replacedKeyFromPropertyName121Dict;
static NSMutableDictionary *newValueFromOldValueDict;
static NSMutableDictionary *objectClassInArrayDict;
static NSMutableDictionary *cachedPropertiesDict;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
replacedKeyFromPropertyNameDict = [NSMutableDictionary dictionary];
replacedKeyFromPropertyName121Dict = [NSMutableDictionary dictionary];
newValueFromOldValueDict = [NSMutableDictionary dictionary];
objectClassInArrayDict = [NSMutableDictionary dictionary];
cachedPropertiesDict = [NSMutableDictionary dictionary];
});
if (key == &MJReplacedKeyFromPropertyNameKey) return replacedKeyFromPropertyNameDict;
if (key == &MJReplacedKeyFromPropertyName121Key) return replacedKeyFromPropertyName121Dict;
if (key == &MJNewValueFromOldValueKey) return newValueFromOldValueDict;
if (key == &MJObjectClassInArrayKey) return objectClassInArrayDict;
if (key == &MJCachedPropertiesKey) return cachedPropertiesDict;
return nil;
}
#pragma mark - ----
+ (id)mj_propertyKey:(NSString *)propertyName
{
MJExtensionAssertParamNotNil2(propertyName, nil);
__block id key = nil;
// key
if ([self respondsToSelector:@selector(mj_replacedKeyFromPropertyName121:)]) {
key = [self mj_replacedKeyFromPropertyName121:propertyName];
}
// block
if (!key) {
[self mj_enumerateAllClasses:^(__unsafe_unretained Class c, BOOL *stop) {
MJReplacedKeyFromPropertyName121 block = objc_getAssociatedObject(c, &MJReplacedKeyFromPropertyName121Key);
if (block) {
key = block(propertyName);
}
if (key) *stop = YES;
}];
}
// key
if ((!key || [key isEqual:propertyName]) && [self respondsToSelector:@selector(mj_replacedKeyFromPropertyName)]) {
key = [self mj_replacedKeyFromPropertyName][propertyName];
}
if (!key || [key isEqual:propertyName]) {
[self mj_enumerateAllClasses:^(__unsafe_unretained Class c, BOOL *stop) {
NSDictionary *dict = objc_getAssociatedObject(c, &MJReplacedKeyFromPropertyNameKey);
if (dict) {
key = dict[propertyName];
}
if (key && ![key isEqual:propertyName]) *stop = YES;
}];
}
// 2.key
if (!key) key = propertyName;
return key;
}
+ (Class)mj_propertyObjectClassInArray:(NSString *)propertyName
{
__block id clazz = nil;
if ([self respondsToSelector:@selector(mj_objectClassInArray)]) {
clazz = [self mj_objectClassInArray][propertyName];
}
if (!clazz) {
[self mj_enumerateAllClasses:^(__unsafe_unretained Class c, BOOL *stop) {
NSDictionary *dict = objc_getAssociatedObject(c, &MJObjectClassInArrayKey);
if (dict) {
clazz = dict[propertyName];
}
if (clazz) *stop = YES;
}];
}
// NSString
if ([clazz isKindOfClass:[NSString class]]) {
clazz = NSClassFromString(clazz);
}
return clazz;
}
#pragma mark - ----
+ (void)mj_enumerateProperties:(MJPropertiesEnumeration)enumeration
{
//
NSArray *cachedProperties = [self mj_properties];
//
BOOL stop = NO;
for (MJProperty *property in cachedProperties) {
enumeration(property, &stop);
if (stop) break;
}
}
#pragma mark -
+ (NSArray *)mj_properties
{
MJExtensionSemaphoreCreate
MJ_LOCK(mje_signalSemaphore);
NSMutableDictionary *cachedInfo = [self mj_propertyDictForKey:&MJCachedPropertiesKey];
NSMutableArray *cachedProperties = cachedInfo[NSStringFromClass(self)];
if (cachedProperties == nil) {
cachedProperties = [NSMutableArray array];
[self mj_enumerateClasses:^(__unsafe_unretained Class c, BOOL *stop) {
// 1.
unsigned int outCount = 0;
objc_property_t *properties = class_copyPropertyList(c, &outCount);
// 2.
for (unsigned int i = 0; i<outCount; i++) {
MJProperty *property = [MJProperty cachedPropertyWithProperty:properties[i]];
// Foundation
if ([MJFoundation isClassFromFoundation:property.srcClass]) continue;
// `hash`, `superclass`, `description`, `debugDescription`
if ([MJFoundation isFromNSObjectProtocolProperty:property.name]) continue;
property.srcClass = c;
[property setOriginKey:[self mj_propertyKey:property.name] forClass:self];
[property setObjectClassInArray:[self mj_propertyObjectClassInArray:property.name] forClass:self];
[cachedProperties addObject:property];
}
// 3.
free(properties);
}];
cachedInfo[NSStringFromClass(self)] = cachedProperties;
}
NSArray *properties = [cachedProperties copy];
MJ_UNLOCK(mje_signalSemaphore);
return properties;
}
#pragma mark -
+ (void)mj_setupNewValueFromOldValue:(MJNewValueFromOldValue)newValueFormOldValue {
MJExtensionSemaphoreCreate
MJ_LOCK(mje_signalSemaphore);
objc_setAssociatedObject(self, &MJNewValueFromOldValueKey, newValueFormOldValue, OBJC_ASSOCIATION_COPY_NONATOMIC);
MJ_UNLOCK(mje_signalSemaphore);
}
+ (id)mj_getNewValueFromObject:(__unsafe_unretained id)object oldValue:(__unsafe_unretained id)oldValue property:(MJProperty *__unsafe_unretained)property{
//
if ([object respondsToSelector:@selector(mj_newValueFromOldValue:property:)]) {
return [object mj_newValueFromOldValue:oldValue property:property];
}
MJExtensionSemaphoreCreate
MJ_LOCK(mje_signalSemaphore);
//
__block id newValue = oldValue;
[self mj_enumerateAllClasses:^(__unsafe_unretained Class c, BOOL *stop) {
MJNewValueFromOldValue block = objc_getAssociatedObject(c, &MJNewValueFromOldValueKey);
if (block) {
newValue = block(object, oldValue, property);
*stop = YES;
}
}];
MJ_UNLOCK(mje_signalSemaphore);
return newValue;
}
+ (void)mj_removeCachedProperties {
MJExtensionSemaphoreCreate
MJ_LOCK(mje_signalSemaphore);
[[self mj_propertyDictForKey:&MJCachedPropertiesKey] removeAllObjects];
MJ_UNLOCK(mje_signalSemaphore);
}
#pragma mark - array model class
+ (void)mj_setupObjectClassInArray:(MJObjectClassInArray)objectClassInArray
{
[self mj_setupBlockReturnValue:objectClassInArray key:&MJObjectClassInArrayKey];
[self mj_removeCachedProperties];
}
#pragma mark - key
+ (void)mj_setupReplacedKeyFromPropertyName:(MJReplacedKeyFromPropertyName)replacedKeyFromPropertyName {
[self mj_setupBlockReturnValue:replacedKeyFromPropertyName key:&MJReplacedKeyFromPropertyNameKey];
[self mj_removeCachedProperties];
}
+ (void)mj_setupReplacedKeyFromPropertyName121:(MJReplacedKeyFromPropertyName121)replacedKeyFromPropertyName121 {
MJExtensionSemaphoreCreate
MJ_LOCK(mje_signalSemaphore);
objc_setAssociatedObject(self, &MJReplacedKeyFromPropertyName121Key, replacedKeyFromPropertyName121, OBJC_ASSOCIATION_COPY_NONATOMIC);
[[self mj_propertyDictForKey:&MJCachedPropertiesKey] removeAllObjects];
MJ_UNLOCK(mje_signalSemaphore);
}
@end
#pragma clang diagnostic pop

View File

@ -0,0 +1,33 @@
//
// NSString+MJExtension.h
// MJExtensionExample
//
// Created by MJ Lee on 15/6/7.
// Copyright (c) 2015年 小码哥. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "MJExtensionConst.h"
@interface NSString (MJExtension)
/**
* 线loveYou -> love_you
*/
- (NSString *)mj_underlineFromCamel;
/**
* 线love_you -> loveYou
*/
- (NSString *)mj_camelFromUnderline;
/**
*
*/
- (NSString *)mj_firstCharUpper;
/**
*
*/
- (NSString *)mj_firstCharLower;
- (BOOL)mj_isPureInt;
- (NSURL *)mj_url;
@end

View File

@ -0,0 +1,80 @@
//
// NSString+MJExtension.m
// MJExtensionExample
//
// Created by MJ Lee on 15/6/7.
// Copyright (c) 2015 . All rights reserved.
//
#import "NSString+MJExtension.h"
@implementation NSString (MJExtension)
- (NSString *)mj_underlineFromCamel
{
if (self.length == 0) return self;
NSMutableString *string = [NSMutableString string];
for (NSUInteger i = 0; i<self.length; i++) {
unichar c = [self characterAtIndex:i];
NSString *cString = [NSString stringWithFormat:@"%c", c];
NSString *cStringLower = [cString lowercaseString];
if ([cString isEqualToString:cStringLower]) {
[string appendString:cStringLower];
} else {
[string appendString:@"_"];
[string appendString:cStringLower];
}
}
return string;
}
- (NSString *)mj_camelFromUnderline
{
if (self.length == 0) return self;
NSMutableString *string = [NSMutableString string];
NSArray *cmps = [self componentsSeparatedByString:@"_"];
for (NSUInteger i = 0; i<cmps.count; i++) {
NSString *cmp = cmps[i];
if (i && cmp.length) {
[string appendString:[NSString stringWithFormat:@"%c", [cmp characterAtIndex:0]].uppercaseString];
if (cmp.length >= 2) [string appendString:[cmp substringFromIndex:1]];
} else {
[string appendString:cmp];
}
}
return string;
}
- (NSString *)mj_firstCharLower
{
if (self.length == 0) return self;
NSMutableString *string = [NSMutableString string];
[string appendString:[NSString stringWithFormat:@"%c", [self characterAtIndex:0]].lowercaseString];
if (self.length >= 2) [string appendString:[self substringFromIndex:1]];
return string;
}
- (NSString *)mj_firstCharUpper
{
if (self.length == 0) return self;
NSMutableString *string = [NSMutableString string];
[string appendString:[NSString stringWithFormat:@"%c", [self characterAtIndex:0]].uppercaseString];
if (self.length >= 2) [string appendString:[self substringFromIndex:1]];
return string;
}
- (BOOL)mj_isPureInt
{
NSScanner *scan = [NSScanner scannerWithString:self];
int val;
return [scan scanInt:&val] && [scan isAtEnd];
}
- (NSURL *)mj_url
{
// [self stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet characterSetWithCharactersInString:@"!$&'()*+,-./:;=?@_~%#[]"]];
#pragma clang diagnostic push
#pragma clang diagnostic ignored"-Wdeprecated-declarations"
return [NSURL URLWithString:(NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)self, (CFStringRef)@"!$&'()*+,-./:;=?@_~%#[]", NULL,kCFStringEncodingUTF8))];
#pragma clang diagnostic pop
}
@end

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSPrivacyTracking</key>
<false/>
<key>NSPrivacyTrackingDomains</key>
<array/>
<key>NSPrivacyAccessedAPITypes</key>
<array/>
<key>NSPrivacyCollectedDataTypes</key>
<array/>
</dict>
</plist>

637
Pods/MJExtension/README.md generated Normal file
View File

@ -0,0 +1,637 @@
MJExtension
===
[![SPM supported](https://img.shields.io/badge/SPM-supported-4BC51D.svg?style=flat)](https://github.com/apple/swift-package-manager)
[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)
[![podversion](https://img.shields.io/cocoapods/v/MJExtension.svg)](https://cocoapods.org/pods/MJExtension)
![Platform](https://img.shields.io/cocoapods/p/MJExtension.svg?style=flat)
- A fast, convenient and nonintrusive conversion framework between JSON and model.
- 转换速度快、使用简单方便的字典转模型框架
[📜✍🏻**Release Notes**: more details](https://github.com/CoderMJLee/MJExtension/releases)
## Contents
* [Getting Started 【开始使用】](#Getting_Started)
* [Features 【能做什么】](#Features)
* [Installation 【安装】](#Installation)
* [Examples 【示例】](#Examples)
* [Usage in Swift](#usage_in_swift)
* [JSON -> Model](#JSON_Model)
* [JSONString -> Model](#JSONString_Model)
* [Model contains model](#Model_contains_model)
* [Model contains model-array](#Model_contains_model_array)
* [Model name - JSON key mapping](#Model_name_JSON_key_mapping)
* [JSON array -> model array](#JSON_array_model_array)
* [Model -> JSON](#Model_JSON)
* [Model array -> JSON array](#Model_array_JSON_array)
* [Core Data](#Core_Data)
* [Coding](#Coding)
* [Secure Coding](#SecureCoding)
* [Camel -> underline](#Camel_underline)
* [NSString -> NSDate, nil -> @""](#NSString_NSDate)
* [NSDate -> NSString](#NSDate_NSString)
* [More use cases](#More_use_cases)
---
## <a id="Getting_Started"></a> Getting Started【开始使用】
### <a id="Features"></a> Features【能做什么】
- MJExtension是一套字典和模型之间互相转换的超轻量级框架
* `JSON` --> `Model`、`Core Data Model`
* `JSONString` --> `Model`、`Core Data Model`
* `Model`、`Core Data Model` --> `JSON`
* `JSON Array` --> `Model Array`、`Core Data Model Array`
* `JSONString` --> `Model Array`、`Core Data Model Array`
* `Model Array`、`Core Data Model Array` --> `JSON Array`
* Coding all properties of a model with only one line of code.
* 只需要一行代码就能实现模型的所有属性进行Coding / SecureCoding归档和解档
### <a id="Installation"></a> Installation【安装】
#### CocoaPods【使用CocoaPods】
```ruby
pod 'MJExtension'
```
#### Carthage
```ruby
github "CoderMJLee/MJExtension"
```
#### Swift Package Manager
Released from [`3.4.0`](https://github.com/CoderMJLee/MJExtension/releases/)
#### Manually【手动导入】
- Drag all source files under folder `MJExtension` to your project.【将`MJExtension`文件夹中的所有源代码拽入项目中】
- Import the main header file`#import "MJExtension.h"`【导入主头文件:`#import "MJExtension.h"`】
## <a id="Examples"></a> Examples【示例】
**Add `MJKeyValue` protocol to your model if needed【如果有需要, 请在模型中加入 `MJKeyValue` 协议】**
### <a id="usage_in_swift"></a> Usage in Swift [关于在Swift中使用MJExtension] ‼️
> Example:
>
> - [Model - MJTester.swift](MJExtensionTests/SwiftModel/MJTester.swift)
>
> - [Usage - SwiftModelTests.swift](MJExtensionTests/SwiftModelTests.swift)
```swift
@objc(MJTester)
@objcMembers
class MJTester: NSObject {
// make sure to use `dynamic` attribute for basic type & must use as Non-Optional & must set initial value
dynamic var isSpecialAgent: Bool = false
dynamic var age: Int = 0
var name: String?
var identifier: String?
}
```
1. `@objc` or `@objcMembers` attributes should be added to class or property for declaration of Objc accessibility [在 Swift4 之后, 请在属性前加 `@objc` 修饰或在类前增加 `@objcMembers`. 以保证 Swift 的属性能够暴露给 Objc 使用. ]
2. If you let `Bool` & `Int` as property type, make sure that using `dynamic` to attribute it. It must be `Non-Optional` type and assign `a default value`.[如果要使用 `Bool``Int` 等 Swfit 专用基本类型, 请使用 `dynamic` 关键字修饰, 类型为 `Non-Optional`, 並且给定初始值.]
> 纯Swift版的JSON与Model转换框架已经开源上架
>
> - [KakaJSON](https://github.com/kakaopensource/KakaJSON)
> - [中文教程](https://www.cnblogs.com/mjios/p/11352776.html)
> - 如果你的项目是用Swift写的Model墙裂推荐使用[KakaJSON](https://github.com/kakaopensource/KakaJSON)
> - 已经对各种常用的数据场景进行了大量的单元测试
> - 简单易用、功能丰富、转换快速
### <a id="JSON_Model"></a> The most simple JSON -> Model【最简单的字典转模型】
```objc
typedef enum {
SexMale,
SexFemale
} Sex;
@interface User : NSObject
@property (copy, nonatomic) NSString *name;
@property (copy, nonatomic) NSString *icon;
@property (assign, nonatomic) unsigned int age;
@property (copy, nonatomic) NSString *height;
@property (strong, nonatomic) NSNumber *money;
@property (assign, nonatomic) Sex sex;
@property (assign, nonatomic, getter=isGay) BOOL gay;
@end
/***********************************************/
NSDictionary *dict = @{
@"name" : @"Jack",
@"icon" : @"lufy.png",
@"age" : @20,
@"height" : @"1.55",
@"money" : @100.9,
@"sex" : @(SexFemale),
@"gay" : @"true"
// @"gay" : @"1"
// @"gay" : @"NO"
};
// JSON -> User
User *user = [User mj_objectWithKeyValues:dict];
NSLog(@"name=%@, icon=%@, age=%zd, height=%@, money=%@, sex=%d, gay=%d", user.name, user.icon, user.age, user.height, user.money, user.sex, user.gay);
// name=Jack, icon=lufy.png, age=20, height=1.550000, money=100.9, sex=1
```
### <a id="JSONString_Model"></a> JSONString -> Model【JSON字符串转模型】
```objc
// 1.Define a JSONString
NSString *jsonString = @"{\"name\":\"Jack\", \"icon\":\"lufy.png\", \"age\":20}";
// 2.JSONString -> User
User *user = [User mj_objectWithKeyValues:jsonString];
// 3.Print user's properties
NSLog(@"name=%@, icon=%@, age=%d", user.name, user.icon, user.age);
// name=Jack, icon=lufy.png, age=20
```
### <a id="Model_contains_model"></a> Model contains model【模型中嵌套模型】
```objc
@interface Status : NSObject
@property (copy, nonatomic) NSString *text;
@property (strong, nonatomic) User *user;
@property (strong, nonatomic) Status *retweetedStatus;
@end
/***********************************************/
NSDictionary *dict = @{
@"text" : @"Agree!Nice weather!",
@"user" : @{
@"name" : @"Jack",
@"icon" : @"lufy.png"
},
@"retweetedStatus" : @{
@"text" : @"Nice weather!",
@"user" : @{
@"name" : @"Rose",
@"icon" : @"nami.png"
}
}
};
// JSON -> Status
Status *status = [Status mj_objectWithKeyValues:dict];
NSString *text = status.text;
NSString *name = status.user.name;
NSString *icon = status.user.icon;
NSLog(@"text=%@, name=%@, icon=%@", text, name, icon);
// text=Agree!Nice weather!, name=Jack, icon=lufy.png
NSString *text2 = status.retweetedStatus.text;
NSString *name2 = status.retweetedStatus.user.name;
NSString *icon2 = status.retweetedStatus.user.icon;
NSLog(@"text2=%@, name2=%@, icon2=%@", text2, name2, icon2);
// text2=Nice weather!, name2=Rose, icon2=nami.png
```
### <a id="Model_contains_model_array"></a> Model contains model-array【模型中有个数组属性数组里面又要装着其他模型】
```objc
@interface Ad : NSObject
@property (copy, nonatomic) NSString *image;
@property (copy, nonatomic) NSString *url;
@end
@interface StatusResult : NSObject
/** Contatins status model */
@property (strong, nonatomic) NSMutableArray *statuses;
/** Contatins ad model */
@property (strong, nonatomic) NSArray *ads;
@property (strong, nonatomic) NSNumber *totalNumber;
@end
/***********************************************/
// Tell MJExtension what type of model will be contained in statuses and ads.
[StatusResult mj_setupObjectClassInArray:^NSDictionary *{
return @{
@"statuses" : @"Status",
// @"statuses" : [Status class],
@"ads" : @"Ad"
// @"ads" : [Ad class]
};
}];
// Equals: StatusResult.m implements +mj_objectClassInArray method.
NSDictionary *dict = @{
@"statuses" : @[
@{
@"text" : @"Nice weather!",
@"user" : @{
@"name" : @"Rose",
@"icon" : @"nami.png"
}
},
@{
@"text" : @"Go camping tomorrow!",
@"user" : @{
@"name" : @"Jack",
@"icon" : @"lufy.png"
}
}
],
@"ads" : @[
@{
@"image" : @"ad01.png",
@"url" : @"http://www.ad01.com"
},
@{
@"image" : @"ad02.png",
@"url" : @"http://www.ad02.com"
}
],
@"totalNumber" : @"2014"
};
// JSON -> StatusResult
StatusResult *result = [StatusResult mj_objectWithKeyValues:dict];
NSLog(@"totalNumber=%@", result.totalNumber);
// totalNumber=2014
// Printing
for (Status *status in result.statuses) {
NSString *text = status.text;
NSString *name = status.user.name;
NSString *icon = status.user.icon;
NSLog(@"text=%@, name=%@, icon=%@", text, name, icon);
}
// text=Nice weather!, name=Rose, icon=nami.png
// text=Go camping tomorrow!, name=Jack, icon=lufy.png
// Printing
for (Ad *ad in result.ads) {
NSLog(@"image=%@, url=%@", ad.image, ad.url);
}
// image=ad01.png, url=http://www.ad01.com
// image=ad02.png, url=http://www.ad02.com
```
### <a id="Model_name_JSON_key_mapping"></a> Model name - JSON key mapping【模型中的属性名和字典中的key不相同(或者需要多级映射)】
```objc
@interface Bag : NSObject
@property (copy, nonatomic) NSString *name;
@property (assign, nonatomic) double price;
@end
@interface Student : NSObject
@property (copy, nonatomic) NSString *ID;
@property (copy, nonatomic) NSString *desc;
@property (copy, nonatomic) NSString *nowName;
@property (copy, nonatomic) NSString *oldName;
@property (copy, nonatomic) NSString *nameChangedTime;
@property (strong, nonatomic) Bag *bag;
@end
/***********************************************/
// How to map
[Student mj_setupReplacedKeyFromPropertyName:^NSDictionary *{
return @{
@"ID" : @"id",
@"desc" : @"description",
@"oldName" : @"name.oldName",
@"nowName" : @"name.newName",
@"nameChangedTime" : @"name.info[1].nameChangedTime",
@"bag" : @"other.bag"
};
}];
// Equals: Student.m implements +mj_replacedKeyFromPropertyName method.
NSDictionary *dict = @{
@"id" : @"20",
@"description" : @"kids",
@"name" : @{
@"newName" : @"lufy",
@"oldName" : @"kitty",
@"info" : @[
@"test-data",
@{
@"nameChangedTime" : @"2013-08"
}
]
},
@"other" : @{
@"bag" : @{
@"name" : @"a red bag",
@"price" : @100.7
}
}
};
// JSON -> Student
Student *stu = [Student mj_objectWithKeyValues:dict];
// Printing
NSLog(@"ID=%@, desc=%@, oldName=%@, nowName=%@, nameChangedTime=%@",
stu.ID, stu.desc, stu.oldName, stu.nowName, stu.nameChangedTime);
// ID=20, desc=kids, oldName=kitty, nowName=lufy, nameChangedTime=2013-08
NSLog(@"bagName=%@, bagPrice=%f", stu.bag.name, stu.bag.price);
// bagName=a red bag, bagPrice=100.700000
```
### <a id="JSON_array_model_array"></a> JSON array -> model array【将一个字典数组转成模型数组】
```objc
NSArray *dictArray = @[
@{
@"name" : @"Jack",
@"icon" : @"lufy.png"
},
@{
@"name" : @"Rose",
@"icon" : @"nami.png"
}
];
// JSON array -> User array
NSArray *userArray = [User mj_objectArrayWithKeyValuesArray:dictArray];
// Printing
for (User *user in userArray) {
NSLog(@"name=%@, icon=%@", user.name, user.icon);
}
// name=Jack, icon=lufy.png
// name=Rose, icon=nami.png
```
### <a id="Model_JSON"></a> Model -> JSON【将一个模型转成字典】
```objc
// New model
User *user = [[User alloc] init];
user.name = @"Jack";
user.icon = @"lufy.png";
Status *status = [[Status alloc] init];
status.user = user;
status.text = @"Nice mood!";
// Status -> JSON
NSDictionary *statusDict = status.mj_keyValues;
NSLog(@"%@", statusDict);
/*
{
text = "Nice mood!";
user = {
icon = "lufy.png";
name = Jack;
};
}
*/
// More complex situation
Student *stu = [[Student alloc] init];
stu.ID = @"123";
stu.oldName = @"rose";
stu.nowName = @"jack";
stu.desc = @"handsome";
stu.nameChangedTime = @"2018-09-08";
Bag *bag = [[Bag alloc] init];
bag.name = @"a red bag";
bag.price = 205;
stu.bag = bag;
NSDictionary *stuDict = stu.mj_keyValues;
NSLog(@"%@", stuDict);
/*
{
ID = 123;
bag = {
name = "\U5c0f\U4e66\U5305";
price = 205;
};
desc = handsome;
nameChangedTime = "2018-09-08";
nowName = jack;
oldName = rose;
}
*/
```
### <a id="Model_array_JSON_array"></a> Model array -> JSON array【将一个模型数组转成字典数组】
```objc
// New model array
User *user1 = [[User alloc] init];
user1.name = @"Jack";
user1.icon = @"lufy.png";
User *user2 = [[User alloc] init];
user2.name = @"Rose";
user2.icon = @"nami.png";
NSArray *userArray = @[user1, user2];
// Model array -> JSON array
NSArray *dictArray = [User mj_keyValuesArrayWithObjectArray:userArray];
NSLog(@"%@", dictArray);
/*
(
{
icon = "lufy.png";
name = Jack;
},
{
icon = "nami.png";
name = Rose;
}
)
*/
```
### <a id="Core_Data"></a> Core Data
```swift
func json2CoreDataObject() {
context.performAndWait {
let object = MJCoreDataTester.mj_object(withKeyValues: Values.testJSONObject, context: context)
// use the object
}
}
func coreDataObject2JSON() {
context.performAndWait {
let dict = coreDataObject.mj_keyValues()
// use dict
}
}
```
### <a id="Coding"></a> Coding (Archive & Unarchive methods are deprecated in iOS 12)
```objc
#import "MJExtension.h"
@implementation MJBag
// NSCoding Implementation
MJCodingImplementation
@end
/***********************************************/
// what properties not to be coded
[MJBag mj_setupIgnoredCodingPropertyNames:^NSArray *{
return @[@"name"];
}];
// Equals: MJBag.m implements +mj_ignoredCodingPropertyNames method.
// Create model
MJBag *bag = [[MJBag alloc] init];
bag.name = @"Red bag";
bag.price = 200.8;
NSString *file = [NSHomeDirectory() stringByAppendingPathComponent:@"Desktop/bag.data"];
// Encoding by archiving
[NSKeyedArchiver archiveRootObject:bag toFile:file];
// Decoding by unarchiving
MJBag *decodedBag = [NSKeyedUnarchiver unarchiveObjectWithFile:file];
NSLog(@"name=%@, price=%f", decodedBag.name, decodedBag.price);
// name=(null), price=200.800000
```
### <a id="SecureCoding"></a> Secure Coding
Using `MJSecureCodingImplementation(class, isSupport)` macro.
```objc
@import MJExtension;
// NSSecureCoding Implementation
MJSecureCodingImplementation(MJBag, YES)
@implementation MJBag
@end
/***********************************************/
// what properties not to be coded
[MJBag mj_setupIgnoredCodingPropertyNames:^NSArray *{
return @[@"name"];
}];
// Equals: MJBag.m implements +mj_ignoredCodingPropertyNames method.
// Create model
MJBag *bag = [[MJBag alloc] init];
bag.name = @"Red bag";
bag.price = 200.8;
bag.isBig = YES;
bag.weight = 200;
NSString *file = [NSTemporaryDirectory() stringByAppendingPathComponent:@"bag.data"];
NSError *error = nil;
// Encoding by archiving
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:bag requiringSecureCoding:YES error:&error];
[data writeToFile:file atomically:true];
// Decoding by unarchiving
NSData *readData = [NSFileManager.defaultManager contentsAtPath:file];
error = nil;
MJBag *decodedBag = [NSKeyedUnarchiver unarchivedObjectOfClass:MJBag.class fromData:readData error:&error];
MJExtensionLog(@"name=%@, price=%f", decodedBag.name, decodedBag.price);
```
### <a id="Camel_underline"></a> Camel -> underline【统一转换属性名比如驼峰转下划线
```objc
// Dog
#import "MJExtension.h"
@implementation Dog
+ (NSString *)mj_replacedKeyFromPropertyName121:(NSString *)propertyName
{
// nickName -> nick_name
return [propertyName mj_underlineFromCamel];
}
@end
// NSDictionary
NSDictionary *dict = @{
@"nick_name" : @"旺财",
@"sale_price" : @"10.5",
@"run_speed" : @"100.9"
};
// NSDictionary -> Dog
Dog *dog = [Dog mj_objectWithKeyValues:dict];
// printing
NSLog(@"nickName=%@, scalePrice=%f runSpeed=%f", dog.nickName, dog.salePrice, dog.runSpeed);
```
### <a id="NSString_NSDate"></a> NSString -> NSDate, nil -> @""【过滤字典的值比如字符串日期处理为NSDate、字符串nil处理为@"")】
```objc
// Book
#import "MJExtension.h"
@implementation Book
- (id)mj_newValueFromOldValue:(id)oldValue property:(MJProperty *)property
{
if ([property.name isEqualToString:@"publisher"]) {
if (oldValue == nil) return @"";
} else if (property.type.typeClass == [NSDate class]) {
NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
fmt.dateFormat = @"yyyy-MM-dd";
return [fmt dateFromString:oldValue];
}
return oldValue;
}
@end
// NSDictionary
NSDictionary *dict = @{
@"name" : @"5分钟突破iOS开发",
@"publishedTime" : @"2011-09-10"
};
// NSDictionary -> Book
Book *book = [Book mj_objectWithKeyValues:dict];
// printing
NSLog(@"name=%@, publisher=%@, publishedTime=%@", book.name, book.publisher, book.publishedTime);
```
### <a id="NSDate_NSString"></a> NSDate -> NSString【模型转字典时, 修改 Date 类型至 String】
```objc
- (void)mj_objectDidConvertToKeyValues:(NSMutableDictionary *)keyValues {
// NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
// formatter.dateFormat = @"yyy-MM-dd";
// should use sharedFormatter for better performance
keyValues[@"publishedTime"] = [sharedFormatter stringFromDate:self.publishedTime];
}
```
### <a id="More_use_cases"></a> More use cases【更多用法】
- Please reference to `NSObject+MJKeyValue.h` and `NSObject+MJCoding.h`
## 期待
* 如果在使用过程中遇到BUG希望你能Issues我谢谢或者尝试下载最新的框架代码看看BUG修复没有
* 如果在使用过程中发现功能不够用希望你能Issues我我非常想为这个框架增加更多好用的功能谢谢
* 如果你想为MJExtension输出代码请拼命Pull Requests我

41
Pods/Manifest.lock generated
View File

@ -82,12 +82,44 @@ PODS:
- MarqueeLabel (4.5.3)
- Masonry (1.1.0)
- MBProgressHUD (1.2.0)
- MJExtension (3.4.2)
- MJRefresh (3.7.9)
- Moya (15.0.0):
- Moya/Core (= 15.0.0)
- Moya/Core (15.0.0):
- Alamofire (~> 5.0)
- ObjectMapper (4.4.2)
- "OpenIMSDK (3.8.3+hotfix.3.1)":
- MJExtension
- "OpenIMSDK/Callbacker (= 3.8.3+hotfix.3.1)"
- "OpenIMSDK/CallbackProxy (= 3.8.3+hotfix.3.1)"
- "OpenIMSDK/Interface (= 3.8.3+hotfix.3.1)"
- "OpenIMSDK/Model (= 3.8.3+hotfix.3.1)"
- "OpenIMSDK/Utils (= 3.8.3+hotfix.3.1)"
- "OpenIMSDKCore (= 3.8.3+3)"
- "OpenIMSDK/Callbacker (3.8.3+hotfix.3.1)":
- MJExtension
- OpenIMSDK/Model
- OpenIMSDK/Utils
- "OpenIMSDKCore (= 3.8.3+3)"
- "OpenIMSDK/CallbackProxy (3.8.3+hotfix.3.1)":
- MJExtension
- OpenIMSDK/Utils
- "OpenIMSDKCore (= 3.8.3+3)"
- "OpenIMSDK/Interface (3.8.3+hotfix.3.1)":
- MJExtension
- OpenIMSDK/Callbacker
- OpenIMSDK/CallbackProxy
- OpenIMSDK/Model
- "OpenIMSDKCore (= 3.8.3+3)"
- "OpenIMSDK/Model (3.8.3+hotfix.3.1)":
- MJExtension
- OpenIMSDK/Utils
- "OpenIMSDKCore (= 3.8.3+3)"
- "OpenIMSDK/Utils (3.8.3+hotfix.3.1)":
- MJExtension
- "OpenIMSDKCore (= 3.8.3+3)"
- "OpenIMSDKCore (3.8.3+3)"
- Popover (1.3.0)
- RxCocoa (6.8.0):
- RxRelay (= 6.8.0)
@ -138,6 +170,7 @@ DEPENDENCIES:
- MJRefresh
- Moya
- ObjectMapper
- OpenIMSDK
- Popover
- RxCocoa
- RxDataSources
@ -179,9 +212,12 @@ SPEC REPOS:
- lottie-ios
- MarqueeLabel
- Masonry
- MJExtension
- MJRefresh
- Moya
- ObjectMapper
- OpenIMSDK
- OpenIMSDKCore
- Popover
- RxCocoa
- RxDataSources
@ -235,9 +271,12 @@ SPEC CHECKSUMS:
MarqueeLabel: 0c57d4c6634e04a6d015af79f7c9a175b2309525
Masonry: 678fab65091a9290e40e2832a55e7ab731aad201
MBProgressHUD: 1b0fb447e80a0fda94808180750e8b78a07b3cd2
MJExtension: e97d164cb411aa9795cf576093a1fa208b4a8dd8
MJRefresh: ff9e531227924c84ce459338414550a05d2aea78
Moya: 138f0573e53411fb3dc17016add0b748dfbd78ee
ObjectMapper: e6e4d91ff7f2861df7aecc536c92d8363f4c9677
OpenIMSDK: c1880296ead605bcac2a289ad0aef9170fe6e6df
OpenIMSDKCore: 75caba22be8ee484011f367711178312bd64a17d
Popover: 10e1d9528f81d9504df984b7b3f491292bc1822d
RxCocoa: 2d33c1e1e5d66492052ad46b11024ae287572880
RxDataSources: aa47cc1ed6c500fa0dfecac5c979b723542d79cf
@ -256,6 +295,6 @@ SPEC CHECKSUMS:
URLNavigator: e9c0426ba6e6ac57f34d018bbf3df840797f984d
ZXSDK: 786338c0a18e98e03eda00699c3bfd2700b97117
PODFILE CHECKSUM: 7d3667576e8d6c3f1a98be0e406f215041cf2eb7
PODFILE CHECKSUM: d9389fd0d3da8895e9ddac8adbec655edaf9bb3d
COCOAPODS: 1.16.2

661
Pods/OpenIMSDK/LICENSE generated Normal file
View File

@ -0,0 +1,661 @@
GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 19 November 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU Affero General Public License is a free, copyleft license for
software and other kinds of works, specifically designed to ensure
cooperation with the community in the case of network server software.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
our General Public Licenses are intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
Developers that use our General Public Licenses protect your rights
with two steps: (1) assert copyright on the software, and (2) offer
you this License which gives you legal permission to copy, distribute
and/or modify the software.
A secondary benefit of defending all users' freedom is that
improvements made in alternate versions of the program, if they
receive widespread use, become available for other developers to
incorporate. Many developers of free software are heartened and
encouraged by the resulting cooperation. However, in the case of
software used on network servers, this result may fail to come about.
The GNU General Public License permits making a modified version and
letting the public access it on a server without ever releasing its
source code to the public.
The GNU Affero General Public License is designed specifically to
ensure that, in such cases, the modified source code becomes available
to the community. It requires the operator of a network server to
provide the source code of the modified version running there to the
users of that server. Therefore, public use of a modified version, on
a publicly accessible server, gives the public access to the source
code of the modified version.
An older license, called the Affero General Public License and
published by Affero, was designed to accomplish similar goals. This is
a different license, not a version of the Affero GPL, but Affero has
released a new version of the Affero GPL which permits relicensing under
this license.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU Affero General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Remote Network Interaction; Use with the GNU General Public License.
Notwithstanding any other provision of this License, if you modify the
Program, your modified version must prominently offer all users
interacting with it remotely through a computer network (if your version
supports such interaction) an opportunity to receive the Corresponding
Source of your version by providing access to the Corresponding Source
from a network server at no charge, through some standard or customary
means of facilitating copying of software. This Corresponding Source
shall include the Corresponding Source for any work covered by version 3
of the GNU General Public License that is incorporated pursuant to the
following paragraph.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the work with which it is combined will remain governed by version
3 of the GNU General Public License.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU Affero General Public License from time to time. Such new versions
will be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU Affero General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU Affero General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU Affero General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If your software can interact with users remotely through a computer
network, you should also make sure that it provides a way for users to
get its source. For example, if your program is a web application, its
interface could display a "Source" link that leads users to an archive
of the code. There are many ways you could offer source, and different
solutions will be better for different programs; see section 13 for the
specific requirements.
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU AGPL, see
<https://www.gnu.org/licenses/>.

View File

@ -0,0 +1,23 @@
//
// CallbackProxy.h
// OpenIMSDK
//
// Created by Snow on 2021/6/24.
//
#import <Foundation/Foundation.h>
#import "OIMDefine.h"
@import OpenIMCore;
NS_ASSUME_NONNULL_BEGIN
@interface CallbackProxy : NSObject <Open_im_sdk_callbackBase>
- (instancetype)initWithOnSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure;
- (void)dispatchMainThread:(void (NS_NOESCAPE ^)(void))todo;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,56 @@
//
// CallbackProxy.m
// OpenIMSDK
//
// Created by Snow on 2021/6/24.
//
#import "CallbackProxy.h"
@interface CallbackProxy() {
OIMSuccessCallback _onSuccess;
OIMFailureCallback _onError;
}
@end
@implementation CallbackProxy
- (instancetype)initWithOnSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
if (self = [super init]) {
_onSuccess = [onSuccess copy];
_onError = [onFailure copy];
}
return self;
}
- (void)onError:(int32_t)errCode errMsg:(NSString * _Nullable)errMsg {
[self dispatchMainThread:^{
if (_onError) {
_onError(errCode, errMsg);
}
}];
}
- (void)onSuccess:(NSString * _Nullable)data {
[self dispatchMainThread:^{
if (_onSuccess) {
_onSuccess(data);
}
}];
}
- (void)dispatchMainThread:(void (NS_NOESCAPE ^)(void))todo {
if ([NSThread isMainThread]) {
todo();
} else {
dispatch_async(dispatch_get_main_queue(), ^{
todo();
});
}
}
@end

View File

@ -0,0 +1,23 @@
//
// SendMessageCallbackProxy.h
// OpenIMSDK
//
// Created by Snow on 2021/6/24.
//
#import <Foundation/Foundation.h>
#import "CallbackProxy.h"
@import OpenIMCore;
NS_ASSUME_NONNULL_BEGIN
@interface SendMessageCallbackProxy : CallbackProxy <Open_im_sdk_callbackSendMsgCallBack>
- (instancetype)initWithOnSuccess:(OIMSuccessCallback)onSuccess
onProgress:(OIMNumberCallback)onProgress
onFailure:(OIMFailureCallback)onFailure;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,56 @@
//
// SendMessageCallbackProxy.m
// OpenIMSDK
//
// Created by Snow on 2021/6/24.
//
#import "SendMessageCallbackProxy.h"
@interface SendMessageCallbackProxy(){
OIMSuccessCallback _onSuccess;
OIMFailureCallback _onFailure;
OIMNumberCallback _onProgress;
}
@end
@implementation SendMessageCallbackProxy
- (instancetype)initWithOnSuccess:(OIMSuccessCallback)onSuccess
onProgress:(OIMNumberCallback)onProgress
onFailure:(OIMFailureCallback)onFailure {
if (self = [super init]) {
_onSuccess = [onSuccess copy];
_onFailure = [onFailure copy];
_onProgress = [onProgress copy];
}
return self;
}
- (void)onError:(int32_t)errCode errMsg:(NSString * _Nullable)errMsg {
[self dispatchMainThread:^{
if (_onFailure) {
_onFailure(errCode, errMsg);
}
}];
}
- (void)onProgress:(long)progress {
[self dispatchMainThread:^{
if (_onProgress) {
_onProgress(progress);
}
}];
}
- (void)onSuccess:(NSString * _Nullable)data {
[self dispatchMainThread:^{
if (_onSuccess) {
_onSuccess(data);
}
}];
}
@end

View File

@ -0,0 +1,30 @@
//
// UploadFileCallbackProxy.h
// OpenIMSDK
//
// Created by x on 2023/6/19.
//
#import <Foundation/Foundation.h>
#import "OIMDefine.h"
@import OpenIMCore;
typedef void (^OIMUploadProgressCallback)(NSInteger saveBytes, NSInteger currentBytes, NSInteger totalBytes);
typedef void (^OIMUploadCompletionCallback)(NSInteger totalBytes, NSString * _Nonnull url, NSInteger putType);
NS_ASSUME_NONNULL_BEGIN
@interface UploadFileCallbackProxy : NSObject <Open_im_sdk_callbackUploadFileCallback>
- (instancetype)initWithOnProgress:(OIMUploadProgressCallback)progress
onCompletion:(OIMUploadCompletionCallback)completion;
@end
@interface UploadLogsCallbackProxy : NSObject <Open_im_sdk_callbackUploadLogProgress>
- (instancetype)initWithOnProgress:(OIMUploadProgressCallback)progress;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,110 @@
//
// UploadFileCallbackProxy.m
// OpenIMSDK
//
// Created by x on 2023/6/19.
//
#import "UploadFileCallbackProxy.h"
@interface UploadFileCallbackProxy() {
OIMUploadProgressCallback onProgress;
OIMUploadCompletionCallback onCompletion;
}
@end
@implementation UploadFileCallbackProxy
- (instancetype)initWithOnProgress:(OIMUploadProgressCallback)progress
onCompletion:(OIMUploadCompletionCallback)completion {
if (self = [super init]) {
onProgress = progress;
onCompletion = completion;
}
return self;
}
- (void)dispatchMainThread:(void (NS_NOESCAPE ^)(void))todo {
if ([NSThread isMainThread]) {
todo();
} else {
dispatch_async(dispatch_get_main_queue(), ^{
todo();
});
}
}
- (void)complete:(int64_t)size url:(NSString *)url typ:(long)typ {
[self dispatchMainThread:^{
onCompletion(size, url, typ);
}];
}
- (void)hashPartComplete:(NSString* _Nullable)partsHash fileHash:(NSString* _Nullable)fileHash {
}
- (void)hashPartProgress:(long)index size:(int64_t)size partHash:(NSString *)partHash {
}
- (void)open:(int64_t)size {
}
- (void)partSize:(int64_t)partSize num:(long)num {
}
- (void)uploadComplete:(int64_t)fileSize streamSize:(int64_t)streamSize storageSize:(int64_t)storageSize {
[self dispatchMainThread:^{
onProgress(fileSize, streamSize, storageSize);
}];
}
- (void)uploadID:(NSString* _Nullable)uploadID {
}
- (void)uploadPartComplete:(long)index partSize:(int64_t)partSize partHash:(NSString *)partHash {
}
@end
@interface UploadLogsCallbackProxy() {
OIMUploadProgressCallback onProgress;
}
@end
@implementation UploadLogsCallbackProxy
- (instancetype)initWithOnProgress:(OIMUploadProgressCallback)progress {
if (self = [super init]) {
onProgress = progress;
}
return self;
}
- (void)onProgress:(int64_t)current size:(int64_t)size {
[self dispatchMainThread:^{
onProgress(current, current, size);
}];
}
- (void)dispatchMainThread:(void (NS_NOESCAPE ^)(void))todo {
if ([NSThread isMainThread]) {
todo();
} else {
dispatch_async(dispatch_get_main_queue(), ^{
todo();
});
}
}
@end

View File

@ -0,0 +1,102 @@
//
// OIMCallbacker+Closure.h
// OpenIMSDK
//
// Created by x on 2022/3/3.
//
#import "OIMCallbacker.h"
NS_ASSUME_NONNULL_BEGIN
@interface OIMCallbacker (Closure)
/**
* Set conversation listeners
* If a conversation changes, it triggers onConversationChanged.
* If a new conversation is added, it triggers onNewConversation.
* If the total unread message count changes, it triggers onTotalUnreadMessageCountChanged.
*
* Actively fetch conversation records at app startup, and later refresh data based on listener callbacks for conversation changes.
*/
- (void)setConversationListenerWithOnSyncServerStart:(OIMBoolCallback)onSyncServerStart
onSyncServerFinish:(OIMBoolCallback)onSyncServerFinish
onSyncServerFailed:(OIMBoolCallback)onSyncServerFailed
onSyncServerProgress:(OIMNumberCallback)onSyncServerProgress
onConversationChanged:(OIMConversationsInfoCallback)onConversationChanged
onNewConversation:(OIMConversationsInfoCallback)onNewConversation
onTotalUnreadMessageCountChanged:(OIMNumberCallback)onTotalUnreadMessageCountChanged;
- (void)setConversationListenerWithOnSyncServerStart:(OIMBoolCallback)onSyncServerStart
onSyncServerFinish:(OIMBoolCallback)onSyncServerFinish
onSyncServerFailed:(OIMBoolCallback)onSyncServerFailed
onSyncServerProgress:(OIMNumberCallback)onSyncServerProgress
onConversationChanged:(OIMConversationsInfoCallback)onConversationChanged
onNewConversation:(OIMConversationsInfoCallback)onNewConversation
onTotalUnreadMessageCountChanged:(OIMNumberCallback)onTotalUnreadMessageCountChanged
onConversationUserInputStatusChanged:(nullable OIMInputStatusChangedCallback)onConversationUserInputStatusChanged;
/**
* Set friend relationship listeners
*
* Callbacks for a friend being added to the blacklist (onBlackAdded),
* a friend being removed from the blacklist (onBlackDeleted),
* accepting a friend request initiated by someone (onFriendApplicationAccepted),
* receiving a friend request initiated by someone (onFriendApplicationAdded),
* deleting a friend request (onFriendApplicationDeleted),
* rejecting a friend request (onFriendApplicationRejected),
* friend profile changes (onFriendInfoChanged),
* added friends (onFriendAdded),
* and deleted friends (onFriendDeleted).
*/
- (void)setFriendListenerWithOnBlackAdded:(OIMBlackInfoCallback)onBlackAdded
onBlackDeleted:(OIMBlackInfoCallback)onBlackDeleted
onFriendApplicationAccepted:(OIMFriendApplicationCallback)onFriendApplicationAccepted
onFriendApplicationAdded:(OIMFriendApplicationCallback)onFriendApplicationAdded
onFriendApplicationDeleted:(OIMFriendApplicationCallback)onFriendApplicationDeleted
onFriendApplicationRejected:(OIMFriendApplicationCallback)onFriendApplicationRejected
onFriendInfoChanged:(OIMFriendInfoCallback)onFriendInfoChanged
onFriendAdded:(OIMFriendInfoCallback)onFriendAdded
onFriendDeleted:(OIMFriendInfoCallback)onFriendDeleted;
/**
* Set group listeners
*/
- (void)setGroupListenerWithOnGroupInfoChanged:(OIMGroupInfoCallback)onGroupInfoChanged
onJoinedGroupAdded:(OIMGroupInfoCallback)onJoinedGroupAdded
onJoinedGroupDeleted:(OIMGroupInfoCallback)onJoinedGroupDeleted
onGroupMemberAdded:(OIMGroupMemberInfoCallback)onGroupMemberAdded
onGroupMemberDeleted:(OIMGroupMemberInfoCallback)onGroupMemberDeleted
onGroupMemberInfoChanged:(OIMGroupMemberInfoCallback)onGroupMemberInfoChanged
onGroupApplicationAdded:(OIMGroupApplicationCallback)onGroupApplicationAdded
onGroupApplicationDeleted:(OIMGroupApplicationCallback)onGroupApplicationDeleted
onGroupApplicationAccepted:(OIMGroupApplicationCallback)onGroupApplicationAccepted
onGroupApplicationRejected:(OIMGroupApplicationCallback)onGroupApplicationRejected
onGroupDismissed:(nullable OIMGroupInfoCallback)onGroupDismissed;
/**
* Add message listeners
*
* When the other party revokes a message (onRecvMessageRevoked), use the callback to replace displayed messages with "xx revoked a message."
* When the other party reads a message (onRecvC2CReadReceipt), use the callback to change the status of read messages.
* For new messages (onRecvNewMessage), add messages to the interface.
*/
- (void)setAdvancedMsgListenerWithOnRecvMessageRevoked:(OIMRevokedCallback)onRecvMessageRevoked
onRecvC2CReadReceipt:(OIMReceiptCallback)onRecvC2CReadReceipt
onRecvGroupReadReceipt:(OIMReceiptCallback)onRecvGroupReadReceipt
onRecvNewMessage:(OIMMessageInfoCallback)onRecvNewMessage;
/**
* User information listeners
*/
- (void)setSelfUserInfoUpdateListener:(OIMUserInfoCallback)onUserInfoUpdate;
- (void)setUserListenerWithUserInfoUpdate:(nullable OIMUserInfoCallback)onUserInfoUpdate
onUserStatusChanged:(nullable OIMUserStatusInfoCallback)onUserStatusChanged;
/**
* Custom messages
*/
- (void)setRecvCustomBusinessMessageListener:(OIMObjectCallback)onRecvCustomBusinessMessage;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,110 @@
//
// OIMCallbacker+Closure.m
// OpenIMSDK
//
// Created by x on 2022/3/3.
//
#import "OIMCallbacker+Closure.h"
@implementation OIMCallbacker (Closure)
- (void)setConversationListenerWithOnSyncServerStart:(OIMBoolCallback)onSyncServerStart
onSyncServerFinish:(OIMBoolCallback)onSyncServerFinish
onSyncServerFailed:(OIMBoolCallback)onSyncServerFailed
onSyncServerProgress:(OIMNumberCallback)onSyncServerProgress
onConversationChanged:(OIMConversationsInfoCallback)onConversationChanged onNewConversation:(OIMConversationsInfoCallback)onNewConversation onTotalUnreadMessageCountChanged:(OIMNumberCallback)onTotalUnreadMessageCountChanged {
[self setConversationListenerWithOnSyncServerStart:onSyncServerStart
onSyncServerFinish:onSyncServerFinish
onSyncServerFailed:onSyncServerFailed
onSyncServerProgress: onSyncServerProgress
onConversationChanged:onConversationChanged
onNewConversation:onNewConversation
onTotalUnreadMessageCountChanged:onTotalUnreadMessageCountChanged
onConversationUserInputStatusChanged:nil];
}
- (void)setConversationListenerWithOnSyncServerStart:(OIMBoolCallback)onSyncServerStart
onSyncServerFinish:(OIMBoolCallback)onSyncServerFinish
onSyncServerFailed:(OIMBoolCallback)onSyncServerFailed
onSyncServerProgress:(OIMNumberCallback)onSyncServerProgress
onConversationChanged:(OIMConversationsInfoCallback)onConversationChanged onNewConversation:(OIMConversationsInfoCallback)onNewConversation onTotalUnreadMessageCountChanged:(OIMNumberCallback)onTotalUnreadMessageCountChanged onConversationUserInputStatusChanged:(OIMInputStatusChangedCallback)onConversationUserInputStatusChanged {
self.syncServerStart = onSyncServerStart;
self.syncServerFinish = onSyncServerFinish;
self.syncServerFailed = onSyncServerFailed;
self.syncServerProgress = onSyncServerProgress;
self.onConversationChanged = onConversationChanged;
self.onNewConversation = onNewConversation;
self.onTotalUnreadMessageCountChanged = onTotalUnreadMessageCountChanged;
self.onConversationUserInputStatusChanged = onConversationUserInputStatusChanged;
}
- (void)setFriendListenerWithOnBlackAdded:(OIMBlackInfoCallback)onBlackAdded
onBlackDeleted:(OIMBlackInfoCallback)onBlackDeleted
onFriendApplicationAccepted:(OIMFriendApplicationCallback)onFriendApplicationAccepted
onFriendApplicationAdded:(OIMFriendApplicationCallback)onFriendApplicationAdded
onFriendApplicationDeleted:(OIMFriendApplicationCallback)onFriendApplicationDeleted
onFriendApplicationRejected:(OIMFriendApplicationCallback)onFriendApplicationRejected
onFriendInfoChanged:(OIMFriendInfoCallback)onFriendInfoChanged
onFriendAdded:(OIMFriendInfoCallback)onFriendAdded
onFriendDeleted:(OIMFriendInfoCallback)onFriendDeleted {
self.onBlackAdded = onBlackAdded;
self.onBlackDeleted = onBlackDeleted;
self.onFriendApplicationAccepted = onFriendApplicationAccepted;
self.onFriendApplicationAdded = onFriendApplicationAdded;
self.onFriendApplicationDeleted = onFriendApplicationDeleted;
self.onFriendApplicationRejected = onFriendApplicationRejected;
self.onFriendInfoChanged = onFriendInfoChanged;
self.onFriendAdded = onFriendAdded;
self.onFriendDeleted = onFriendDeleted;
}
- (void)setGroupListenerWithOnGroupInfoChanged:(OIMGroupInfoCallback)onGroupInfoChanged
onJoinedGroupAdded:(OIMGroupInfoCallback)onJoinedGroupAdded
onJoinedGroupDeleted:(OIMGroupInfoCallback)onJoinedGroupDeleted
onGroupMemberAdded:(OIMGroupMemberInfoCallback)onGroupMemberAdded
onGroupMemberDeleted:(OIMGroupMemberInfoCallback)onGroupMemberDeleted
onGroupMemberInfoChanged:(OIMGroupMemberInfoCallback)onGroupMemberInfoChanged
onGroupApplicationAdded:(OIMGroupApplicationCallback)onGroupApplicationAdded
onGroupApplicationDeleted:(OIMGroupApplicationCallback)onGroupApplicationDeleted
onGroupApplicationAccepted:(OIMGroupApplicationCallback)onGroupApplicationAccepted
onGroupApplicationRejected:(OIMGroupApplicationCallback)onGroupApplicationRejected
onGroupDismissed:(OIMGroupInfoCallback)onGroupDismissed {
self.onGroupInfoChanged = onGroupInfoChanged;
self.onJoinedGroupAdded = onJoinedGroupAdded;
self.onJoinedGroupDeleted = onJoinedGroupDeleted;
self.onGroupMemberAdded = onGroupMemberAdded;
self.onGroupMemberInfoChanged = onGroupMemberInfoChanged;
self.onGroupApplicationAdded = onGroupApplicationAdded;
self.onGroupApplicationDeleted = onGroupApplicationDeleted;
self.onGroupApplicationAccepted = onGroupApplicationAccepted;
self.onGroupApplicationRejected = onGroupApplicationRejected;
self.onGroupDismissed = onGroupDismissed;
}
- (void)setAdvancedMsgListenerWithOnRecvMessageRevoked:(OIMRevokedCallback)onRecvMessageRevoked
onRecvC2CReadReceipt:(OIMReceiptCallback)onRecvC2CReadReceipt
onRecvGroupReadReceipt:(OIMReceiptCallback)onRecvGroupReadReceipt
onRecvNewMessage:(OIMMessageInfoCallback)onRecvNewMessage {
self.onRecvMessageRevoked = onRecvMessageRevoked;
self.onRecvC2CReadReceipt = onRecvC2CReadReceipt;
self.onRecvGroupReadReceipt = onRecvGroupReadReceipt;
self.onRecvNewMessage = onRecvNewMessage;
}
- (void)setSelfUserInfoUpdateListener:(OIMUserInfoCallback)onUserInfoUpdate {
[self setUserListenerWithUserInfoUpdate:onUserInfoUpdate onUserStatusChanged:nil];
}
- (void)setUserListenerWithUserInfoUpdate:(OIMUserInfoCallback)onUserInfoUpdate
onUserStatusChanged:(OIMUserStatusInfoCallback)onUserStatusChanged {
self.onSelfInfoUpdated = onUserInfoUpdate;
self.onUserStatusChanged = onUserStatusChanged;
}
- (void)setRecvCustomBusinessMessageListener:(OIMObjectCallback)onRecvCustomBusinessMessage {
self.onRecvCustomBusinessMessage = onRecvCustomBusinessMessage;
}
@end

View File

@ -0,0 +1,461 @@
//
// OIMCallbacker.h
// OpenIMSDK
//
// Created by x on 2022/2/11.
//
#import <Foundation/Foundation.h>
#import <MJExtension/MJExtension.h>
#import "OIMDefine.h"
#import "OIMUserInfo.h"
#import "OIMFullUserInfo.h"
#import "OIMFriendApplication.h"
#import "OIMGroupApplicationInfo.h"
#import "OIMGroupInfo.h"
#import "OIMGroupMemberInfo.h"
#import "OIMConversationInfo.h"
#import "OIMMessageInfo.h"
#import "OIMSearchParam.h"
#import "OIMSearchResultInfo.h"
#import "OIMSimpleResultInfo.h"
#import "OIMSimpleRequstInfo.h"
@import OpenIMCore;
NS_ASSUME_NONNULL_BEGIN
typedef void (^OIMSimpleResultCallback)(OIMSimpleResultInfo * _Nullable result);
typedef void (^OIMSimpleResultsCallback)(NSArray <OIMSimpleResultInfo *> * _Nullable results);
typedef void (^OIMUserInfoCallback)(OIMUserInfo * _Nullable userInfo);
typedef void (^OIMUsersInfoCallback)(NSArray <OIMUserInfo *> * _Nullable usersInfo);
typedef void (^OIMUsersCallback)(NSArray <OIMPublicUserInfo *> * _Nullable userInfos);
typedef void (^OIMPublicUserInfoCallback)(OIMPublicUserInfo * _Nullable userInfo);
typedef void (^OIMPublicUsersInfoCallback)(NSArray <OIMPublicUserInfo *> * _Nullable userInfos);
typedef void (^OIMBlacksInfoCallback)(NSArray <OIMBlackInfo *> * _Nullable blackInfos);
typedef void (^OIMUserStatusInfoCallback)(OIMUserStatusInfo * _Nullable statusInfo);
typedef void (^OIMUserStatusInfosCallback)(NSArray <OIMUserStatusInfo *> * _Nullable statusInfos);
typedef void (^OIMFriendApplicationCallback)(OIMFriendApplication * _Nullable friendApplication);
typedef void (^OIMFriendApplicationsCallback)(NSArray <OIMFriendApplication *> * _Nullable friendApplications);
typedef void (^OIMFriendInfoCallback)(OIMFriendInfo * _Nullable friendInfo);
typedef void (^OIMFriendsInfoCallback)(NSArray<OIMFriendInfo *> * _Nullable friendInfo);
typedef void (^OIMBlackInfoCallback)(OIMBlackInfo * _Nullable blackInfo);
typedef void (^OIMBlacksInfoCallback)(NSArray<OIMBlackInfo *> * _Nullable blackInfo);
typedef void (^OIMSearchUsersInfoCallback)(NSArray<OIMSearchFriendsInfo *> * _Nullable usersInfo);
typedef void (^OIMGroupApplicationCallback)(OIMGroupApplicationInfo * _Nullable groupApplication);
typedef void (^OIMGroupsApplicationCallback)(NSArray <OIMGroupApplicationInfo *> * _Nullable groupsInfo);
typedef void (^OIMGroupInfoCallback)(OIMGroupInfo * _Nullable groupInfo);
typedef void (^OIMGroupsInfoCallback)(NSArray <OIMGroupInfo *> * _Nullable groupsInfo);
typedef void (^OIMGroupMemberInfoCallback)(OIMGroupMemberInfo * _Nullable groupMemberInfo);
typedef void (^OIMGroupMembersInfoCallback)(NSArray <OIMGroupMemberInfo *> * _Nullable groupMembersInfo);
typedef void (^OIMConversationsInfoCallback)(NSArray <OIMConversationInfo *> * _Nullable conversations);
typedef void (^OIMConversationInfoCallback)(OIMConversationInfo * _Nullable conversation);
typedef void (^OIMConversationNotDisturbInfoCallback)(NSArray <OIMConversationNotDisturbInfo *> * _Nullable conversations);
typedef void (^OIMMessageInfoCallback)(OIMMessageInfo * _Nullable message);
typedef void (^OIMMessagesInfoCallback)(NSArray <OIMMessageInfo *> * _Nullable messages);
typedef void (^OIMMessageSearchCallback)(OIMSearchResultInfo * _Nullable result);
typedef void (^OIMReceiptCallback)(NSArray <OIMReceiptInfo *> * _Nullable msgReceiptList);
typedef void (^OIMRevokedCallback)(OIMMessageRevokedInfo * _Nullable msgRovoked);
typedef void (^OIMGetAdvancedHistoryMessageListCallback)(OIMGetAdvancedHistoryMessageListInfo * _Nullable result);
typedef void (^OIMInputStatusChangedCallback)(NSArray<NSNumber *> *inputStatesChangedData);
/// IMSDK Core Callbacks
@protocol OIMSDKListener <NSObject>
@optional
/**
* SDK is connecting to the server.
*/
- (void)onConnecting;
/**
* SDK has successfully connected to the server.
*/
- (void)onConnectSuccess;
/**
* SDK connection to the server has failed.
*/
- (void)onConnectFailed:(NSInteger)code err:(NSString *)err;
/**
* The current user has been kicked offline. You can show a UI notification to the user.
*/
- (void)onKickedOffline;
/**
* Token has expired while online: You need to generate a new UserToken and re-login.
*/
- (void)onUserTokenExpired;
- (void)onUserTokenInvalid:(NSString *)errMsg;
@end
/// User Status Callbacks
@protocol OIMUserListener <NSObject>
@optional
/**
* User information has been updated.
*/
- (void)onSelfInfoUpdated:(OIMUserInfo *)info;
/**
* User status has changed.
*/
- (void)onUserStatusChanged:(OIMUserStatusInfo *)info;
@end
/// Profile and Relationship Callbacks
@protocol OIMFriendshipListener <NSObject>
@optional
/**
* New friend application notification.
*/
- (void)onFriendApplicationAdded:(OIMFriendApplication *)application;
/**
* Friend application has been rejected.
*/
- (void)onFriendApplicationRejected:(OIMFriendApplication *)application;
/**
* Friend application has been accepted.
*/
- (void)onFriendApplicationAccepted:(OIMFriendApplication *)application;
/**
* Friend application has been deleted.
*/
- (void)onFriendApplicationDeleted:(OIMFriendApplication *)application;
/**
* New friend notification.
*/
- (void)onFriendAdded:(OIMFriendInfo *)info;
/**
* Friend deletion notification.
*/
- (void)onFriendDeleted:(OIMFriendInfo *)info;
/**
* Friend profile change notification.
*/
- (void)onFriendInfoChanged:(OIMFriendInfo *)info;
/**
* New blacklist notification.
*/
- (void)onBlackAdded:(OIMBlackInfo *)info;
/**
* Blacklist deletion notification.
*/
- (void)onBlackDeleted:(OIMBlackInfo *)info;
@end
/// IMSDK Group Event Callbacks
@protocol OIMGroupListener <NSObject>
@optional
/**
* New member joined the group.
*/
- (void)onGroupMemberAdded:(OIMGroupMemberInfo *)memberInfo;
/**
* Member left the group.
*/
- (void)onGroupMemberDeleted:(OIMGroupMemberInfo *)memberInfo;
/**
* Information of a member in the group has changed.
*/
- (void)onGroupMemberInfoChanged:(OIMGroupMemberInfo *)changeInfo;
/**
* Callback for group addition.
*/
- (void)onJoinedGroupAdded:(OIMGroupInfo *)groupInfo;
/**
* Callback for group removal.
*/
- (void)onJoinedGroupDeleted:(OIMGroupInfo *)groupInfo;
/**
* Information of a group that the user has joined has been modified.
*/
- (void)onGroupInfoChanged:(OIMGroupInfo *)changeInfo;
/**
* Group application has been accepted.
*/
- (void)onGroupApplicationAccepted:(OIMGroupApplicationInfo *)groupApplication;
/**
* Someone has applied to join the group.
*/
- (void)onGroupApplicationAdded:(OIMGroupApplicationInfo *)groupApplication;
/**
* Group application has been deleted.
*/
- (void)onGroupApplicationDeleted:(OIMGroupApplicationInfo *)groupApplication;
/**
* Group application has been rejected.
*/
- (void)onGroupApplicationRejected:(OIMGroupApplicationInfo *)groupApplication;
/**
* Group has been disbanded.
*/
- (void)onGroupDismissed:(OIMGroupInfo *)changeInfo;
@end
/// Conversation Event Callbacks
@protocol OIMConversationListener <NSObject>
@optional
/**
* Synchronization with the server has started for conversations.
*/
- (void)onSyncServerStart:(BOOL)reInstall;
- (void)onSyncServerProgress:(NSInteger)progress;
/**
* Synchronization with the server for conversations has completed.
*/
- (void)onSyncServerFinish:(BOOL)reInstall;
/**
* Synchronization with the server for conversations has failed.
*/
- (void)onSyncServerFailed:(BOOL)reInstall;
/**
* New conversations have been added.
*/
- (void)onNewConversation:(NSArray <OIMConversationInfo *> *)conversations;
/**
* Key information of certain conversations has changed.
*/
- (void)onConversationChanged:(NSArray <OIMConversationInfo *> *)conversations;
/**
* Notification of changes in the total unread message count of conversations.
*/
- (void)onTotalUnreadMessageCountChanged:(NSInteger)totalUnreadCount;
/**
* User input status updates.
*/
- (void)onConversationUserInputStatusChanged:(OIMInputStatusChangedData *)inputStatusChangedData;
@end
/// Advanced Message Listener
@protocol OIMAdvancedMsgListener <NSObject>
@optional
/**
* Received a new message.
*/
- (void)onRecvNewMessage:(OIMMessageInfo *)msg;
/**
* Read receipt for one-on-one messages.
*/
- (void)onRecvC2CReadReceipt:(NSArray<OIMReceiptInfo *> *)receiptList;
/**
* Read receipt for group chat messages.
*/
- (void)onRecvGroupReadReceipt:(NSArray<OIMReceiptInfo *> *)groupMsgReceiptList;
/**
* Received a message retraction.
*/
- (void)onRecvMessageRevoked:(OIMMessageRevokedInfo *)messageRevoked;
- (void)onMsgDeleted:(OIMMessageInfo *)message;
- (void)onRecvOnlineOnlyMessage:(OIMMessageInfo *)message;
@end
/// Custom Business Callbacks for IM
@protocol OIMCustomBusinessListener <NSObject>
@optional
- (void)onRecvCustomBusinessMessage:(NSDictionary <NSString *, id>* _Nullable)businessMessage;
@end
@interface OIMCallbacker : NSObject
<
Open_im_sdk_callbackOnConnListener,
Open_im_sdk_callbackOnAdvancedMsgListener,
Open_im_sdk_callbackOnConversationListener,
Open_im_sdk_callbackOnFriendshipListener,
Open_im_sdk_callbackOnGroupListener,
Open_im_sdk_callbackOnUserListener,
Open_im_sdk_callbackOnCustomBusinessListener
>
+ (instancetype)callbacker;
- (void)setListener;
/// Connection Listener
/// Set during InitSDK, called when the IM connection status changes.
@property (nonatomic, nullable, copy) OIMVoidCallback connecting;
@property (nonatomic, nullable, copy) OIMFailureCallback connectFailure;
@property (nonatomic, nullable, copy) OIMVoidCallback connectSuccess;
@property (nonatomic, nullable, copy) OIMVoidCallback kickedOffline;
@property (nonatomic, nullable, copy) OIMVoidCallback userTokenExpired;
@property (nonatomic, nullable, copy) OIMStringCallback userTokenInvalid;
/**
* Add IM SDK listener.
*/
- (void)addIMSDKListener:(id<OIMSDKListener>)listener;
/**
* Remove IM SDK listener.
*/
- (void)removeIMSDKListener:(id<OIMSDKListener>)listener;
/// User Listener
/// Set after a successful InitSDK and before Login, called when the personal profile of the logged-in user changes.
@property (nonatomic, nullable, copy) OIMUserInfoCallback onSelfInfoUpdated;
@property (nonatomic, nullable, copy) OIMUserStatusInfoCallback onUserStatusChanged;
/**
* Add User listener.
*/
- (void)addUserListener:(id<OIMUserListener>)listener NS_SWIFT_NAME(addUserListener(listener:));
/**
* Remove User listener.
*/
- (void)removeUserListener:(id<OIMUserListener>)listener NS_SWIFT_NAME(removeUserListener(listener:));
/// Friendship Listener
/// Set after a successful InitSDK and before Login, called when friend-related information changes.
@property (nonatomic, nullable, copy) OIMFriendApplicationCallback onFriendApplicationAdded;
@property (nonatomic, nullable, copy) OIMFriendApplicationCallback onFriendApplicationDeleted;
@property (nonatomic, nullable, copy) OIMFriendApplicationCallback onFriendApplicationAccepted;
@property (nonatomic, nullable, copy) OIMFriendApplicationCallback onFriendApplicationRejected;
@property (nonatomic, nullable, copy) OIMFriendInfoCallback onFriendAdded;
@property (nonatomic, nullable, copy) OIMFriendInfoCallback onFriendDeleted;
@property (nonatomic, nullable, copy) OIMFriendInfoCallback onFriendInfoChanged;
@property (nonatomic, nullable, copy) OIMBlackInfoCallback onBlackAdded;
@property (nonatomic, nullable, copy) OIMBlackInfoCallback onBlackDeleted;
/**
* Add Friendship listener.
*/
- (void)addFriendListener:(id<OIMFriendshipListener>)listener NS_SWIFT_NAME(addFriendListener(listener:));
/**
* Remove Friendship listener.
*/
- (void)removeFriendListener:(id<OIMFriendshipListener>)listener NS_SWIFT_NAME(removeFriendListener(listener:));
/// Group Listener
/// Set after a successful InitSDK and before Login, called when group-related information changes.
@property (nonatomic, nullable, copy) OIMGroupInfoCallback onGroupInfoChanged;
@property (nonatomic, nullable, copy) OIMGroupInfoCallback onJoinedGroupAdded;
@property (nonatomic, nullable, copy) OIMGroupInfoCallback onJoinedGroupDeleted;
@property (nonatomic, nullable, copy) OIMGroupMemberInfoCallback onGroupMemberAdded;
@property (nonatomic, nullable, copy) OIMGroupMemberInfoCallback onGroupMemberDeleted;
@property (nonatomic, nullable, copy) OIMGroupMemberInfoCallback onGroupMemberInfoChanged;
@property (nonatomic, nullable, copy) OIMGroupApplicationCallback onGroupApplicationAdded;
@property (nonatomic, nullable, copy) OIMGroupApplicationCallback onGroupApplicationDeleted;
@property (nonatomic, nullable, copy) OIMGroupApplicationCallback onGroupApplicationAccepted;
@property (nonatomic, nullable, copy) OIMGroupApplicationCallback onGroupApplicationRejected;
@property (nonatomic, nullable, copy) OIMGroupInfoCallback onGroupDismissed;
/**
* Set group listener.
*/
- (void)addGroupListener:(id<OIMGroupListener>)listener NS_SWIFT_NAME(addGroupListener(listener:));
/**
* Remove group listener.
*/
- (void)removeGroupListener:(id<OIMGroupListener>)listener NS_SWIFT_NAME(removeGroupListener(listener:));
/// Conversation Listener
/// Set after a successful InitSDK and before Login, called when conversation-related information changes.
@property (nonatomic, nullable, copy) OIMBoolCallback syncServerStart;
@property (nonatomic, nullable, copy) OIMBoolCallback syncServerFinish;
@property (nonatomic, nullable, copy) OIMBoolCallback syncServerFailed;
@property (nonatomic, nullable, copy) OIMNumberCallback syncServerProgress;
@property (nonatomic, nullable, copy) OIMConversationsInfoCallback onNewConversation;
@property (nonatomic, nullable, copy) OIMConversationsInfoCallback onConversationChanged;
@property (nonatomic, nullable, copy) OIMNumberCallback onTotalUnreadMessageCountChanged;
@property (nonatomic, nullable, copy) OIMInputStatusChangedCallback onConversationUserInputStatusChanged;
/**
* Add conversation listener.
*/
- (void)addConversationListener:(id<OIMConversationListener>)listener NS_SWIFT_NAME(addConversationListener(listener:));
/**
* Remove conversation listener.
*/
- (void)removeConversationListener:(id<OIMConversationListener>)listener NS_SWIFT_NAME(removeConversationListener(listener:));
/// Message Listener
/// Set after a successful InitSDK and before Login, called when message-related information changes.
@property (nonatomic, nullable, copy) OIMMessageInfoCallback onRecvNewMessage;
@property (nonatomic, nullable, copy) OIMReceiptCallback onRecvC2CReadReceipt;
@property (nonatomic, nullable, copy) OIMReceiptCallback onRecvGroupReadReceipt;
@property (nonatomic, nullable, copy) OIMRevokedCallback onRecvMessageRevoked;
@property (nonatomic, nullable, copy) OIMMessageInfoCallback onMessageDeleted;
/**
* Add advanced message event listener.
*/
- (void)addAdvancedMsgListener:(id<OIMAdvancedMsgListener>)listener NS_SWIFT_NAME(addAdvancedMsgListener(listener:));
/**
* Remove advanced message event listener.
*/
- (void)removeAdvancedMsgListener:(id<OIMAdvancedMsgListener>)listener NS_SWIFT_NAME(removeAdvancedMsgListener(listener:));
/// Custom Business Message Listener
@property (nonatomic, nullable, copy) OIMObjectCallback onRecvCustomBusinessMessage;
/**
* Add IM listener for custom business events.
*/
- (void)addCustomBusinessListener:(id<OIMCustomBusinessListener>)listener NS_SWIFT_NAME(addCustomBusinessListener(listener:));
/**
* Remove IM listener for custom business events.
*/
- (void)removeCustomBusinessListener:(id<OIMCustomBusinessListener>)listener NS_SWIFT_NAME(removeCustomBusinessListener(listener:));
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,674 @@
//
// OIMCallbacker.m
// OpenIMSDK
//
// Created by x on 2021/2/11.
//
#import "OIMCallbacker.h"
#import "OIMGCDMulticastDelegate.h"
@interface OIMCallbacker ()
@property (nonatomic, strong) OIMGCDMulticastDelegate <OIMSDKListener> *sdkListeners;
@property (nonatomic, strong) OIMGCDMulticastDelegate <OIMUserListener> *userListeners;
@property (nonatomic, strong) OIMGCDMulticastDelegate <OIMFriendshipListener> *friendshipListeners;
@property (nonatomic, strong) OIMGCDMulticastDelegate <OIMGroupListener> *groupListeners;
@property (nonatomic, strong) OIMGCDMulticastDelegate <OIMConversationListener> *conversationListeners;
@property (nonatomic, strong) OIMGCDMulticastDelegate <OIMAdvancedMsgListener> *advancedMsgListeners;
@property (nonatomic, strong) OIMGCDMulticastDelegate <OIMCustomBusinessListener> *customBusinessListeners;
@end
@implementation OIMCallbacker
+ (instancetype)callbacker {
return [OIMCallbacker new];
}
- (void)setListener {
Open_im_sdkSetUserListener(self);
Open_im_sdkSetFriendListener(self);
Open_im_sdkSetGroupListener(self);
Open_im_sdkSetConversationListener(self);
Open_im_sdkSetAdvancedMsgListener(self);
Open_im_sdkSetCustomBusinessListener(self);
}
- (void)dispatchMainThread:(void (NS_NOESCAPE ^)(void))todo {
if ([NSThread isMainThread]) {
todo();
} else {
dispatch_async(dispatch_get_main_queue(), ^{
todo();
});
}
}
#pragma mark -
#pragma mark - Listeners getter
- (OIMGCDMulticastDelegate<OIMSDKListener> *)sdkListeners {
if (_sdkListeners == nil) {
_sdkListeners = (OIMGCDMulticastDelegate <OIMSDKListener> *)[[OIMGCDMulticastDelegate alloc] init];
}
return _sdkListeners;
}
- (OIMGCDMulticastDelegate<OIMUserListener> *)userListeners {
if (_userListeners == nil) {
_userListeners = (OIMGCDMulticastDelegate <OIMUserListener> *)[[OIMGCDMulticastDelegate alloc] init];
}
return _userListeners;
}
- (OIMGCDMulticastDelegate<OIMFriendshipListener> *)friendshipListeners {
if (_friendshipListeners == nil) {
_friendshipListeners = (OIMGCDMulticastDelegate <OIMFriendshipListener> *)[[OIMGCDMulticastDelegate alloc] init];
}
return _friendshipListeners;
}
- (OIMGCDMulticastDelegate<OIMGroupListener> *)groupListeners {
if (_groupListeners == nil) {
_groupListeners = (OIMGCDMulticastDelegate <OIMGroupListener> *)[[OIMGCDMulticastDelegate alloc] init];
}
return _groupListeners;
}
- (OIMGCDMulticastDelegate<OIMConversationListener> *)conversationListeners {
if (_conversationListeners == nil) {
_conversationListeners = (OIMGCDMulticastDelegate <OIMConversationListener> *)[[OIMGCDMulticastDelegate alloc] init];
}
return _conversationListeners;
}
- (OIMGCDMulticastDelegate<OIMAdvancedMsgListener> *)advancedMsgListeners {
if (_advancedMsgListeners == nil) {
_advancedMsgListeners = (OIMGCDMulticastDelegate <OIMAdvancedMsgListener> *)[[OIMGCDMulticastDelegate alloc] init];
}
return _advancedMsgListeners;
}
- (OIMGCDMulticastDelegate<OIMCustomBusinessListener> *)customBusinessListeners {
if (_customBusinessListeners == nil) {
_customBusinessListeners = (OIMGCDMulticastDelegate <OIMCustomBusinessListener> *)[[OIMGCDMulticastDelegate alloc] init];
}
return _customBusinessListeners;
}
#pragma mark -
#pragma mark - Add/Remove listener
- (void)addIMSDKListener:(id<OIMSDKListener>)listener {
[self.sdkListeners addDelegate:listener delegateQueue:dispatch_get_main_queue()];
}
- (void)removeIMSDKListener:(id<OIMSDKListener>)listener {
[self.sdkListeners removeDelegate:listener];
}
- (void)addUserListener:(id<OIMUserListener>)listener {
[self.userListeners addDelegate:listener delegateQueue:dispatch_get_main_queue()];
}
- (void)removeUserListener:(id<OIMUserListener>)listener {
[self.userListeners removeDelegate:listener];
}
- (void)addFriendListener:(id<OIMFriendshipListener>)listener {
[self.friendshipListeners addDelegate:listener delegateQueue:dispatch_get_main_queue()];
}
- (void)removeFriendListener:(id<OIMFriendshipListener>)listener {
[self.friendshipListeners removeDelegate:listener];
}
- (void)addGroupListener:(id<OIMGroupListener>)listener {
[self.groupListeners addDelegate:listener delegateQueue:dispatch_get_main_queue()];
}
- (void)removeGroupListener:(id<OIMGroupListener>)listener {
[self.groupListeners removeDelegate:listener];
}
- (void)addConversationListener:(id<OIMConversationListener>)listener {
[self.conversationListeners addDelegate:listener delegateQueue:dispatch_get_main_queue()];
}
- (void)removeConversationListener:(id<OIMConversationListener>)listener {
[self.conversationListeners removeDelegate:listener];
}
- (void)addAdvancedMsgListener:(id<OIMAdvancedMsgListener>)listener {
[self.advancedMsgListeners addDelegate:listener delegateQueue:dispatch_get_main_queue()];
}
- (void)removeAdvancedMsgListener:(id<OIMAdvancedMsgListener>)listener {
[self.advancedMsgListeners removeDelegate:listener];
}
- (void)addCustomBusinessListener:(id<OIMCustomBusinessListener>)listener {
[self.customBusinessListeners addDelegate:listener delegateQueue:dispatch_get_main_queue()];
}
- (void)removeCustomBusinessListener:(id<OIMCustomBusinessListener>)listener {
[self.customBusinessListeners removeDelegate:listener];
}
#pragma mark -
#pragma mark - Connection
- (void)onConnectFailed:(int32_t)errCode errMsg:(NSString * _Nullable)errMsg {
[self dispatchMainThread:^{
if (self.connectFailure) {
self.connectFailure(errCode, errMsg);
}
[self.sdkListeners onConnectFailed:errCode err:errMsg];
}];
}
- (void)onConnectSuccess {
[self dispatchMainThread:^{
if (self.connectSuccess) {
self.connectSuccess();
}
[self.sdkListeners onConnectSuccess];
}];
}
- (void)onConnecting {
[self dispatchMainThread:^{
if (self.connecting) {
self.connecting();
}
[self.sdkListeners onConnecting];
}];
}
- (void)onKickedOffline {
[self dispatchMainThread:^{
if (self.kickedOffline) {
self.kickedOffline();
}
[self.sdkListeners onKickedOffline];
}];
}
- (void)onUserTokenExpired {
[self dispatchMainThread:^{
if (self.userTokenExpired) {
self.userTokenExpired();
}
[self.sdkListeners onUserTokenExpired];
}];
}
- (void)onUserTokenInvalid:(NSString *)errMsg {
[self dispatchMainThread:^{
if (self.userTokenInvalid) {
self.userTokenInvalid(errMsg);
}
[self.sdkListeners onUserTokenInvalid:errMsg];
}];
}
#pragma mark -
#pragma mark - User
- (void)onSelfInfoUpdated:(NSString * _Nullable)userInfo {
OIMUserInfo *info = [OIMUserInfo mj_objectWithKeyValues:userInfo];
[self dispatchMainThread:^{
if (self.onSelfInfoUpdated) {
self.onSelfInfoUpdated(info);
}
[self.userListeners onSelfInfoUpdated:info];
}];
}
- (void)onUserStatusChanged:(NSString *)statusMap {
OIMUserStatusInfo *info = [OIMUserStatusInfo mj_objectWithKeyValues:statusMap];
[self dispatchMainThread:^{
if (self.onUserStatusChanged) {
self.onUserStatusChanged(info);
}
[self.userListeners onUserStatusChanged:info];
}];
}
- (void)onUserCommandAdd:(NSString * _Nullable)userCommand {
}
- (void)onUserCommandDelete:(NSString * _Nullable)userCommand {
}
- (void)onUserCommandUpdate:(NSString * _Nullable)userCommand {
}
#pragma mark -
#pragma mark - Friend
- (void)onFriendApplicationAdded:(NSString * _Nullable)friendApplication {
OIMFriendApplication *info = [OIMFriendApplication mj_objectWithKeyValues:friendApplication];
[self dispatchMainThread:^{
if (self.onFriendApplicationAdded) {
self.onFriendApplicationAdded(info);
}
[self.friendshipListeners onFriendApplicationAdded:info];
}];
}
- (void)onFriendApplicationRejected:(NSString * _Nullable)friendApplication {
OIMFriendApplication *info = [OIMFriendApplication mj_objectWithKeyValues:friendApplication];
[self dispatchMainThread:^{
if (self.onFriendApplicationRejected) {
self.onFriendApplicationRejected(info);
}
[self.friendshipListeners onFriendApplicationRejected:info];
}];
}
- (void)onFriendApplicationAccepted:(NSString * _Nullable)friendApplication {
OIMFriendApplication *info = [OIMFriendApplication mj_objectWithKeyValues:friendApplication];
[self dispatchMainThread:^{
if (self.onFriendApplicationAccepted) {
self.onFriendApplicationAccepted(info);
}
[self.friendshipListeners onFriendApplicationAccepted:info];
}];
}
- (void)onFriendApplicationDeleted:(NSString * _Nullable)friendApplication {
OIMFriendApplication *info = [OIMFriendApplication mj_objectWithKeyValues:friendApplication];
[self dispatchMainThread:^{
if (self.onFriendApplicationDeleted) {
self.onFriendApplicationDeleted(info);
}
[self.friendshipListeners onFriendApplicationDeleted:info];
}];
}
- (void)onFriendAdded:(NSString * _Nullable)friendInfo {
OIMFriendInfo *info = [OIMFriendInfo mj_objectWithKeyValues:friendInfo];
[self dispatchMainThread:^{
if (self.onFriendAdded) {
self.onFriendAdded(info);
}
[self.friendshipListeners onFriendAdded:info];
}];
}
- (void)onFriendDeleted:(NSString * _Nullable)friendInfo {
OIMFriendInfo *info = [OIMFriendInfo mj_objectWithKeyValues:friendInfo];
[self dispatchMainThread:^{
if (self.onFriendDeleted) {
self.onFriendDeleted(info);
}
[self.friendshipListeners onFriendDeleted:info];
}];
}
- (void)onFriendInfoChanged:(NSString * _Nullable)friendInfo {
OIMFriendInfo *info = [OIMFriendInfo mj_objectWithKeyValues:friendInfo];
[self dispatchMainThread:^{
if (self.onFriendInfoChanged) {
self.onFriendInfoChanged(info);
}
[self.friendshipListeners onFriendInfoChanged:info];
}];
}
- (void)onBlackAdded:(NSString* _Nullable)blackInfo {
OIMBlackInfo *info = [OIMBlackInfo mj_objectWithKeyValues:blackInfo];
[self dispatchMainThread:^{
if (self.onBlackAdded) {
self.onBlackAdded(info);
}
[self.friendshipListeners onBlackAdded:info];
}];
}
- (void)onBlackDeleted:(NSString * _Nullable)blackInfo {
OIMBlackInfo *info = [OIMBlackInfo mj_objectWithKeyValues:blackInfo];
[self dispatchMainThread:^{
if (self.onBlackDeleted) {
self.onBlackDeleted(info);
}
[self.friendshipListeners onBlackDeleted:info];
}];
}
#pragma mark -
#pragma mark - Group
- (void)onGroupMemberAdded:(NSString * _Nullable)groupMemberInfo {
OIMGroupMemberInfo *info = [OIMGroupMemberInfo mj_objectWithKeyValues:groupMemberInfo];
[self dispatchMainThread:^{
if (self.onGroupMemberAdded) {
self.onGroupMemberAdded(info);
}
[self.groupListeners onGroupMemberAdded:info];
}];
}
- (void)onGroupMemberDeleted:(NSString * _Nullable)groupMemberInfo {
OIMGroupMemberInfo *info = [OIMGroupMemberInfo mj_objectWithKeyValues:groupMemberInfo];
[self dispatchMainThread:^{
if (self.onGroupMemberDeleted) {
self.onGroupMemberDeleted(info);
}
[self.groupListeners onGroupMemberDeleted:info];
}];
}
- (void)onGroupMemberInfoChanged:(NSString * _Nullable)groupMemberInfo {
OIMGroupMemberInfo *info = [OIMGroupMemberInfo mj_objectWithKeyValues:groupMemberInfo];
[self dispatchMainThread:^{
if (self.onGroupMemberInfoChanged) {
self.onGroupMemberInfoChanged(info);
}
[self.groupListeners onGroupMemberInfoChanged:info];
}];
}
- (void)onGroupInfoChanged:(NSString * _Nullable)groupInfo {
OIMGroupInfo *info = [OIMGroupInfo mj_objectWithKeyValues:groupInfo];
[self dispatchMainThread:^{
if (self.onGroupInfoChanged) {
self.onGroupInfoChanged(info);
}
[self.groupListeners onGroupInfoChanged:info];
}];
}
- (void)onJoinedGroupAdded:(NSString * _Nullable)groupInfo {
OIMGroupInfo *info = [OIMGroupInfo mj_objectWithKeyValues:groupInfo];
[self dispatchMainThread:^{
if (self.onJoinedGroupAdded) {
self.onJoinedGroupAdded(info);
}
[self.groupListeners onJoinedGroupAdded:info];
}];
}
- (void)onJoinedGroupDeleted:(NSString * _Nullable)groupInfo {
OIMGroupInfo *info = [OIMGroupInfo mj_objectWithKeyValues:groupInfo];
[self dispatchMainThread:^{
if (self.onJoinedGroupDeleted) {
self.onJoinedGroupDeleted(info);
}
[self.groupListeners onJoinedGroupDeleted:info];
}];
}
- (void)onGroupApplicationAccepted:(NSString * _Nullable)groupApplication {
OIMGroupApplicationInfo *info = [OIMGroupApplicationInfo mj_objectWithKeyValues:groupApplication];
[self dispatchMainThread:^{
if (self.onGroupApplicationAccepted) {
self.onGroupApplicationAccepted(info);
}
[self.groupListeners onGroupApplicationAccepted:info];
}];
}
- (void)onGroupApplicationAdded:(NSString * _Nullable)groupApplication {
OIMGroupApplicationInfo *info = [OIMGroupApplicationInfo mj_objectWithKeyValues:groupApplication];
[self dispatchMainThread:^{
if (self.onGroupApplicationAdded) {
self.onGroupApplicationAdded(info);
}
[self.groupListeners onGroupApplicationAdded:info];
}];
}
- (void)onGroupApplicationDeleted:(NSString * _Nullable)groupApplication {
OIMGroupApplicationInfo *info = [OIMGroupApplicationInfo mj_objectWithKeyValues:groupApplication];
[self dispatchMainThread:^{
if (self.onGroupApplicationDeleted) {
self.onGroupApplicationDeleted(info);
}
[self.groupListeners onGroupApplicationDeleted:info];
}];
}
- (void)onGroupApplicationRejected:(NSString * _Nullable)groupApplication {
OIMGroupApplicationInfo *info = [OIMGroupApplicationInfo mj_objectWithKeyValues:groupApplication];
[self dispatchMainThread:^{
if (self.onGroupApplicationRejected) {
self.onGroupApplicationRejected(info);
}
[self.groupListeners onGroupApplicationRejected:info];
}];
}
- (void)onGroupDismissed:(NSString *)groupInfo {
OIMGroupInfo *info = [OIMGroupInfo mj_objectWithKeyValues:groupInfo];
[self dispatchMainThread:^{
if (self.onGroupDismissed) {
self.onGroupDismissed(info);
}
[self.groupListeners onGroupDismissed:info];
}];
}
#pragma mark -
#pragma mark - Message
- (void)onRecvC2CReadReceipt:(NSString * _Nullable)msgReceiptList {
NSArray *receipts = [OIMReceiptInfo mj_objectArrayWithKeyValuesArray:msgReceiptList];
[self dispatchMainThread:^{
if (self.onRecvC2CReadReceipt) {
self.onRecvC2CReadReceipt(receipts);
}
[self.advancedMsgListeners onRecvC2CReadReceipt:receipts];
}];
}
- (void)onRecvGroupReadReceipt:(NSString* _Nullable)groupMsgReceiptList {
NSArray *receipts = [OIMReceiptInfo mj_objectArrayWithKeyValuesArray:groupMsgReceiptList];
[self dispatchMainThread:^{
if (self.onRecvGroupReadReceipt) {
self.onRecvGroupReadReceipt(receipts);
}
[self.advancedMsgListeners onRecvGroupReadReceipt:receipts];
}];
}
- (void)onNewRecvMessageRevoked:(NSString *)messageRevoked {
OIMMessageRevokedInfo *revoked = [OIMMessageRevokedInfo mj_objectWithKeyValues:messageRevoked];
[self dispatchMainThread:^{
if (self.onRecvMessageRevoked) {
self.onRecvMessageRevoked(revoked);
}
[self.advancedMsgListeners onRecvMessageRevoked:revoked];
}];
}
- (void)onRecvNewMessage:(NSString * _Nullable)message {
OIMMessageInfo *msg = [OIMMessageInfo mj_objectWithKeyValues:message];
[self dispatchMainThread:^{
if (self.onRecvNewMessage) {
self.onRecvNewMessage(msg);
}
[self.advancedMsgListeners onRecvNewMessage:msg];
}];
}
- (void)onMsgDeleted:(NSString *)message {
OIMMessageInfo *msg = [OIMMessageInfo mj_objectWithKeyValues:message];
[self dispatchMainThread:^{
if (self.onMessageDeleted) {
self.onMessageDeleted(msg);
}
[self.advancedMsgListeners onMsgDeleted:msg];
}];
}
- (void)onRecvOfflineNewMessage:(NSString * _Nullable)message {
}
- (void)onRecvOnlineOnlyMessage:(NSString *)message {
OIMMessageInfo *msg = [OIMMessageInfo mj_objectWithKeyValues:message];
[self dispatchMainThread:^{
[self.advancedMsgListeners onRecvOnlineOnlyMessage:msg];
}];
}
#pragma mark -
#pragma mark - Conversation
- (void)onConversationChanged:(NSString * _Nullable)conversationList {
NSArray *tConversations = [OIMConversationInfo mj_objectArrayWithKeyValuesArray:conversationList];
[self dispatchMainThread:^{
if (self.onConversationChanged) {
self.onConversationChanged(tConversations);
}
[self.conversationListeners onConversationChanged:tConversations];
}];
}
- (void)onNewConversation:(NSString * _Nullable)conversationList {
NSArray *tConversations = [OIMConversationInfo mj_objectArrayWithKeyValuesArray:conversationList];
[self dispatchMainThread:^{
if (self.onNewConversation) {
self.onNewConversation(tConversations);
}
[self.conversationListeners onNewConversation:tConversations];
}];
}
- (void)onSyncServerFailed:(BOOL)reinstalled {
[self dispatchMainThread:^{
if (self.syncServerFailed) {
self.syncServerFailed(reinstalled);
}
[self.conversationListeners onSyncServerFailed:reinstalled];
}];
}
- (void)onSyncServerFinish:(BOOL)reinstalled {
[self dispatchMainThread:^{
if (self.syncServerFinish) {
self.syncServerFinish(reinstalled);
}
[self.conversationListeners onSyncServerFinish:reinstalled];
}];
}
- (void)onSyncServerStart:(BOOL)reinstalled {
[self dispatchMainThread:^{
if (self.syncServerStart) {
self.syncServerStart(reinstalled);
}
[self.conversationListeners onSyncServerStart:reinstalled];
}];
}
- (void)onSyncServerProgress:(long)progress {
[self dispatchMainThread:^{
if (self.syncServerStart) {
self.syncServerStart(progress);
}
[self.conversationListeners onSyncServerProgress:progress];
}];
}
- (void)onTotalUnreadMessageCountChanged:(int32_t)totalUnreadCount {
[self dispatchMainThread:^{
if (self.onTotalUnreadMessageCountChanged) {
self.onTotalUnreadMessageCountChanged(totalUnreadCount);
}
[self.conversationListeners onTotalUnreadMessageCountChanged:totalUnreadCount];
}];
}
- (void)onConversationUserInputStatusChanged:(NSString *)change {
}
#pragma mark -
#pragma mark - CustomBusiness
- (void)onRecvCustomBusinessMessage:(NSString *)businessMessage {
NSDictionary *output = businessMessage.mj_JSONObject;
[self dispatchMainThread:^{
if (self.onRecvCustomBusinessMessage) {
self.onRecvCustomBusinessMessage(output);
}
[self.customBusinessListeners onRecvCustomBusinessMessage:output];
}];
}
@end

View File

@ -0,0 +1,58 @@
#import <Foundation/Foundation.h>
@class OIMGCDMulticastDelegateEnumerator;
/**
* This class provides multicast delegate functionality. That is:
* - it provides a means for managing a list of delegates
* - any method invocations to an instance of this class are automatically forwarded to all delegates
*
* For example:
*
* // Make this method call on every added delegate (there may be several)
* [multicastDelegate cog:self didFindThing:thing];
*
* This allows multiple delegates to be added to an xmpp stream or any xmpp module,
* which in turn makes development easier as there can be proper separation of logically different code sections.
*
* In addition, this makes module development easier,
* as multiple delegates can usually be handled in a manner similar to the traditional single delegate paradigm.
*
* This class also provides proper support for GCD queues.
* So each delegate specifies which queue they would like their delegate invocations to be dispatched onto.
*
* All delegate dispatching is done asynchronously (which is a critically important architectural design).
**/
NS_ASSUME_NONNULL_BEGIN
@interface OIMGCDMulticastDelegate : NSObject
- (void)addDelegate:(id)delegate delegateQueue:(dispatch_queue_t)delegateQueue;
- (void)removeDelegate:(id)delegate delegateQueue:(nullable dispatch_queue_t)delegateQueue;
- (void)removeDelegate:(id)delegate;
- (void)removeAllDelegates;
@property (nonatomic, readonly) NSUInteger count;
- (NSUInteger)countOfClass:(Class)aClass;
- (NSUInteger)countForSelector:(SEL)aSelector;
- (BOOL)hasDelegateThatRespondsToSelector:(SEL)aSelector;
- (OIMGCDMulticastDelegateEnumerator *)delegateEnumerator;
@end
@interface OIMGCDMulticastDelegateEnumerator : NSObject
@property (nonatomic, readonly) NSUInteger count;
- (NSUInteger)countOfClass:(Class)aClass;
- (NSUInteger)countForSelector:(SEL)aSelector;
- (BOOL)getNextDelegate:(id _Nullable * _Nonnull)delPtr delegateQueue:(dispatch_queue_t _Nullable * _Nonnull)dqPtr;
- (BOOL)getNextDelegate:(id _Nullable * _Nonnull)delPtr delegateQueue:(dispatch_queue_t _Nullable * _Nonnull)dqPtr ofClass:(Class)aClass;
- (BOOL)getNextDelegate:(id _Nullable * _Nonnull)delPtr delegateQueue:(dispatch_queue_t _Nullable * _Nonnull)dqPtr forSelector:(SEL)aSelector;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,654 @@
#import "OIMGCDMulticastDelegate.h"
#import <libkern/OSAtomic.h>
#if __has_feature(objc_arc_weak) && !TARGET_OS_IPHONE
#import <AppKit/AppKit.h>
#endif
#if ! __has_feature(objc_arc)
#warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
#endif
/**
* How does this class work?
*
* In theory, this class is very straight-forward.
* It provides a way for multiple delegates to be called, each on its own delegate queue.
*
* In other words, any delegate method call to this class
* will get forwarded (dispatch_async'd) to each added delegate.
*
* Important note concerning thread-safety:
*
* This class is designed to be used from within a single dispatch queue.
* In other words, it is NOT thread-safe, and should only be used from within the external dedicated dispatch_queue.
**/
@interface OIMGCDMulticastDelegateNode : NSObject {
@private
#if __has_feature(objc_arc_weak)
__weak id delegate;
#if !TARGET_OS_IPHONE
__unsafe_unretained id unsafeDelegate; // Some classes don't support weak references yet (e.g. NSWindowController)
#endif
#else
__unsafe_unretained id delegate;
#endif
dispatch_queue_t delegateQueue;
}
- (id)initWithDelegate:(id)delegate delegateQueue:(dispatch_queue_t)delegateQueue;
#if __has_feature(objc_arc_weak)
@property (/* atomic */ readwrite, weak) id delegate;
#if !TARGET_OS_IPHONE
@property (/* atomic */ readwrite, unsafe_unretained) id unsafeDelegate;
#endif
#else
@property (/* atomic */ readwrite, unsafe_unretained) id delegate;
#endif
@property (nonatomic, readonly) dispatch_queue_t delegateQueue;
@end
@interface OIMGCDMulticastDelegate ()
{
NSMutableArray *delegateNodes;
}
- (NSInvocation *)duplicateInvocation:(NSInvocation *)origInvocation;
@end
@interface OIMGCDMulticastDelegateEnumerator ()
{
NSUInteger numNodes;
NSUInteger currentNodeIndex;
NSArray *delegateNodes;
}
- (id)initFromDelegateNodes:(NSMutableArray *)inDelegateNodes;
@end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@implementation OIMGCDMulticastDelegate
- (id)init
{
if ((self = [super init]))
{
delegateNodes = [[NSMutableArray alloc] init];
}
return self;
}
- (void)addDelegate:(id)delegate delegateQueue:(dispatch_queue_t)delegateQueue
{
if (delegate == nil) return;
if (delegateQueue == NULL) return;
OIMGCDMulticastDelegateNode *node =
[[OIMGCDMulticastDelegateNode alloc] initWithDelegate:delegate delegateQueue:delegateQueue];
[delegateNodes addObject:node];
}
- (void)removeDelegate:(id)delegate delegateQueue:(dispatch_queue_t)delegateQueue
{
if (delegate == nil) return;
NSUInteger i;
for (i = [delegateNodes count]; i > 0; i--)
{
OIMGCDMulticastDelegateNode *node = delegateNodes[i - 1];
id nodeDelegate = node.delegate;
#if __has_feature(objc_arc_weak) && !TARGET_OS_IPHONE
if (nodeDelegate == [NSNull null])
nodeDelegate = node.unsafeDelegate;
#endif
if (delegate == nodeDelegate)
{
if ((delegateQueue == NULL) || (delegateQueue == node.delegateQueue))
{
// Recall that this node may be retained by a OIMGCDMulticastDelegateEnumerator.
// The enumerator is a thread-safe snapshot of the delegate list at the moment it was created.
// To properly remove this node from list, and from the list(s) of any enumerators,
// we nullify the delegate via the atomic property.
//
// However, the delegateQueue is not modified.
// The thread-safety is hinged on the atomic delegate property.
// The delegateQueue is expected to properly exist until the node is deallocated.
node.delegate = nil;
#if __has_feature(objc_arc_weak) && !TARGET_OS_IPHONE
node.unsafeDelegate = nil;
#endif
[delegateNodes removeObjectAtIndex:(i-1)];
}
}
}
}
- (void)removeDelegate:(id)delegate
{
[self removeDelegate:delegate delegateQueue:NULL];
}
- (void)removeAllDelegates
{
for (OIMGCDMulticastDelegateNode *node in delegateNodes)
{
node.delegate = nil;
#if __has_feature(objc_arc_weak) && !TARGET_OS_IPHONE
node.unsafeDelegate = nil;
#endif
}
[delegateNodes removeAllObjects];
}
- (NSUInteger)count
{
return [delegateNodes count];
}
- (NSUInteger)countOfClass:(Class)aClass
{
NSUInteger count = 0;
for (OIMGCDMulticastDelegateNode *node in delegateNodes)
{
id nodeDelegate = node.delegate;
#if __has_feature(objc_arc_weak) && !TARGET_OS_IPHONE
if (nodeDelegate == [NSNull null])
nodeDelegate = node.unsafeDelegate;
#endif
if ([nodeDelegate isKindOfClass:aClass])
{
count++;
}
}
return count;
}
- (NSUInteger)countForSelector:(SEL)aSelector
{
NSUInteger count = 0;
for (OIMGCDMulticastDelegateNode *node in delegateNodes)
{
id nodeDelegate = node.delegate;
#if __has_feature(objc_arc_weak) && !TARGET_OS_IPHONE
if (nodeDelegate == [NSNull null])
nodeDelegate = node.unsafeDelegate;
#endif
if ([nodeDelegate respondsToSelector:aSelector])
{
count++;
}
}
return count;
}
- (BOOL)hasDelegateThatRespondsToSelector:(SEL)aSelector
{
for (OIMGCDMulticastDelegateNode *node in delegateNodes)
{
id nodeDelegate = node.delegate;
#if __has_feature(objc_arc_weak) && !TARGET_OS_IPHONE
if (nodeDelegate == [NSNull null])
nodeDelegate = node.unsafeDelegate;
#endif
if ([nodeDelegate respondsToSelector:aSelector])
{
return YES;
}
}
return NO;
}
- (OIMGCDMulticastDelegateEnumerator *)delegateEnumerator
{
return [[OIMGCDMulticastDelegateEnumerator alloc] initFromDelegateNodes:delegateNodes];
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
for (OIMGCDMulticastDelegateNode *node in delegateNodes)
{
id nodeDelegate = node.delegate;
#if __has_feature(objc_arc_weak) && !TARGET_OS_IPHONE
if (nodeDelegate == [NSNull null])
nodeDelegate = node.unsafeDelegate;
#endif
NSMethodSignature *result = [nodeDelegate methodSignatureForSelector:aSelector];
if (result != nil)
{
return result;
}
}
// This causes a crash...
// return [super methodSignatureForSelector:aSelector];
// This also causes a crash...
// return nil;
return [[self class] instanceMethodSignatureForSelector:@selector(doNothing)];
}
- (void)forwardInvocation:(NSInvocation *)origInvocation
{
SEL selector = [origInvocation selector];
BOOL foundNilDelegate = NO;
for (OIMGCDMulticastDelegateNode *node in delegateNodes)
{
id nodeDelegate = node.delegate;
#if __has_feature(objc_arc_weak) && !TARGET_OS_IPHONE
if (nodeDelegate == [NSNull null])
nodeDelegate = node.unsafeDelegate;
#endif
if ([nodeDelegate respondsToSelector:selector])
{
// All delegates MUST be invoked ASYNCHRONOUSLY.
NSInvocation *dupInvocation = [self duplicateInvocation:origInvocation];
dispatch_async(node.delegateQueue, ^{ @autoreleasepool {
[dupInvocation invokeWithTarget:nodeDelegate];
}});
}
else if (nodeDelegate == nil)
{
foundNilDelegate = YES;
}
}
if (foundNilDelegate)
{
// At lease one weak delegate reference disappeared.
// Remove nil delegate nodes from the list.
//
// This is expected to happen very infrequently.
// This is why we handle it separately (as it requires allocating an indexSet).
NSMutableIndexSet *indexSet = [[NSMutableIndexSet alloc] init];
NSUInteger i = 0;
for (OIMGCDMulticastDelegateNode *node in delegateNodes)
{
id nodeDelegate = node.delegate;
#if __has_feature(objc_arc_weak) && !TARGET_OS_IPHONE
if (nodeDelegate == [NSNull null])
nodeDelegate = node.unsafeDelegate;
#endif
if (nodeDelegate == nil)
{
[indexSet addIndex:i];
}
i++;
}
[delegateNodes removeObjectsAtIndexes:indexSet];
}
}
- (void)doesNotRecognizeSelector:(SEL)aSelector
{
// Prevent NSInvalidArgumentException
}
- (void)doNothing {}
- (void)dealloc
{
[self removeAllDelegates];
}
- (NSInvocation *)duplicateInvocation:(NSInvocation *)origInvocation
{
NSMethodSignature *methodSignature = [origInvocation methodSignature];
NSInvocation *dupInvocation = [NSInvocation invocationWithMethodSignature:methodSignature];
[dupInvocation setSelector:[origInvocation selector]];
NSUInteger i, count = [methodSignature numberOfArguments];
for (i = 2; i < count; i++)
{
const char *type = [methodSignature getArgumentTypeAtIndex:i];
if (*type == *@encode(BOOL))
{
BOOL value;
[origInvocation getArgument:&value atIndex:i];
[dupInvocation setArgument:&value atIndex:i];
}
else if (*type == *@encode(char) || *type == *@encode(unsigned char))
{
char value;
[origInvocation getArgument:&value atIndex:i];
[dupInvocation setArgument:&value atIndex:i];
}
else if (*type == *@encode(short) || *type == *@encode(unsigned short))
{
short value;
[origInvocation getArgument:&value atIndex:i];
[dupInvocation setArgument:&value atIndex:i];
}
else if (*type == *@encode(int) || *type == *@encode(unsigned int))
{
int value;
[origInvocation getArgument:&value atIndex:i];
[dupInvocation setArgument:&value atIndex:i];
}
else if (*type == *@encode(long) || *type == *@encode(unsigned long))
{
long value;
[origInvocation getArgument:&value atIndex:i];
[dupInvocation setArgument:&value atIndex:i];
}
else if (*type == *@encode(long long) || *type == *@encode(unsigned long long))
{
long long value;
[origInvocation getArgument:&value atIndex:i];
[dupInvocation setArgument:&value atIndex:i];
}
else if (*type == *@encode(double))
{
double value;
[origInvocation getArgument:&value atIndex:i];
[dupInvocation setArgument:&value atIndex:i];
}
else if (*type == *@encode(float))
{
float value;
[origInvocation getArgument:&value atIndex:i];
[dupInvocation setArgument:&value atIndex:i];
}
else if (*type == '@')
{
void *value;
[origInvocation getArgument:&value atIndex:i];
[dupInvocation setArgument:&value atIndex:i];
}
else if (*type == '^')
{
void *block;
[origInvocation getArgument:&block atIndex:i];
[dupInvocation setArgument:&block atIndex:i];
}
else
{
NSString *selectorStr = NSStringFromSelector([origInvocation selector]);
NSString *format = @"Argument %lu to method %@ - Type(%c) not supported";
NSString *reason = [NSString stringWithFormat:format, (unsigned long)(i - 2), selectorStr, *type];
[[NSException exceptionWithName:NSInvalidArgumentException reason:reason userInfo:nil] raise];
}
}
[dupInvocation retainArguments];
return dupInvocation;
}
@end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@implementation OIMGCDMulticastDelegateNode
@synthesize delegate; // atomic
#if __has_feature(objc_arc_weak) && !TARGET_OS_IPHONE
@synthesize unsafeDelegate; // atomic
#endif
@synthesize delegateQueue; // non-atomic
#if __has_feature(objc_arc_weak) && !TARGET_OS_IPHONE
static BOOL SupportsWeakReferences(id delegate)
{
// From Apple's documentation:
//
// > Which classes dont support weak references?
// >
// > You cannot currently create weak references to instances of the following classes:
// >
// > NSATSTypesetter, NSColorSpace, NSFont, NSFontManager, NSFontPanel, NSImage, NSMenuView,
// > NSParagraphStyle, NSSimpleHorizontalTypesetter, NSTableCellView, NSTextView, NSViewController,
// > NSWindow, and NSWindowController.
// >
// > In addition, in OS X no classes in the AV Foundation framework support weak references.
//
// NSMenuView is deprecated (and not available to 64-bit applications).
// NSSimpleHorizontalTypesetter is an internal class.
if ([delegate isKindOfClass:[NSATSTypesetter class]]) return NO;
if ([delegate isKindOfClass:[NSColorSpace class]]) return NO;
if ([delegate isKindOfClass:[NSFont class]]) return NO;
if ([delegate isKindOfClass:[NSFontManager class]]) return NO;
if ([delegate isKindOfClass:[NSFontPanel class]]) return NO;
if ([delegate isKindOfClass:[NSImage class]]) return NO;
if ([delegate isKindOfClass:[NSParagraphStyle class]]) return NO;
if ([delegate isKindOfClass:[NSTableCellView class]]) return NO;
if ([delegate isKindOfClass:[NSTextView class]]) return NO;
if ([delegate isKindOfClass:[NSViewController class]]) return NO;
if ([delegate isKindOfClass:[NSWindow class]]) return NO;
if ([delegate isKindOfClass:[NSWindowController class]]) return NO;
return YES;
}
#endif
- (id)initWithDelegate:(id)inDelegate delegateQueue:(dispatch_queue_t)inDelegateQueue
{
if ((self = [super init]))
{
#if __has_feature(objc_arc_weak) && !TARGET_OS_IPHONE
{
if (SupportsWeakReferences(inDelegate))
{
delegate = inDelegate;
delegateQueue = inDelegateQueue;
}
else
{
delegate = [NSNull null];
unsafeDelegate = inDelegate;
delegateQueue = inDelegateQueue;
}
}
#else
{
delegate = inDelegate;
delegateQueue = inDelegateQueue;
}
#endif
#if !OS_OBJECT_USE_OBJC
if (delegateQueue)
dispatch_retain(delegateQueue);
#endif
}
return self;
}
- (void)dealloc
{
#if !OS_OBJECT_USE_OBJC
if (delegateQueue)
dispatch_release(delegateQueue);
#endif
}
@end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@implementation OIMGCDMulticastDelegateEnumerator
- (id)initFromDelegateNodes:(NSMutableArray *)inDelegateNodes
{
if ((self = [super init]))
{
delegateNodes = [inDelegateNodes copy];
numNodes = [delegateNodes count];
currentNodeIndex = 0;
}
return self;
}
- (NSUInteger)count
{
return numNodes;
}
- (NSUInteger)countOfClass:(Class)aClass
{
NSUInteger count = 0;
for (OIMGCDMulticastDelegateNode *node in delegateNodes)
{
id nodeDelegate = node.delegate;
#if __has_feature(objc_arc_weak) && !TARGET_OS_IPHONE
if (nodeDelegate == [NSNull null])
nodeDelegate = node.unsafeDelegate;
#endif
if ([nodeDelegate isKindOfClass:aClass])
{
count++;
}
}
return count;
}
- (NSUInteger)countForSelector:(SEL)aSelector
{
NSUInteger count = 0;
for (OIMGCDMulticastDelegateNode *node in delegateNodes)
{
id nodeDelegate = node.delegate;
#if __has_feature(objc_arc_weak) && !TARGET_OS_IPHONE
if (nodeDelegate == [NSNull null])
nodeDelegate = node.unsafeDelegate;
#endif
if ([nodeDelegate respondsToSelector:aSelector])
{
count++;
}
}
return count;
}
- (BOOL)getNextDelegate:(id *)delPtr delegateQueue:(dispatch_queue_t *)dqPtr
{
while (currentNodeIndex < numNodes)
{
OIMGCDMulticastDelegateNode *node = delegateNodes[currentNodeIndex];
currentNodeIndex++;
id nodeDelegate = node.delegate; // snapshot atomic property
#if __has_feature(objc_arc_weak) && !TARGET_OS_IPHONE
if (nodeDelegate == [NSNull null])
nodeDelegate = node.unsafeDelegate;
#endif
if (nodeDelegate)
{
if (delPtr) *delPtr = nodeDelegate;
if (dqPtr) *dqPtr = node.delegateQueue;
return YES;
}
}
return NO;
}
- (BOOL)getNextDelegate:(id *)delPtr delegateQueue:(dispatch_queue_t *)dqPtr ofClass:(Class)aClass
{
while (currentNodeIndex < numNodes)
{
OIMGCDMulticastDelegateNode *node = delegateNodes[currentNodeIndex];
currentNodeIndex++;
id nodeDelegate = node.delegate; // snapshot atomic property
#if __has_feature(objc_arc_weak) && !TARGET_OS_IPHONE
if (nodeDelegate == [NSNull null])
nodeDelegate = node.unsafeDelegate;
#endif
if ([nodeDelegate isKindOfClass:aClass])
{
if (delPtr) *delPtr = nodeDelegate;
if (dqPtr) *dqPtr = node.delegateQueue;
return YES;
}
}
return NO;
}
- (BOOL)getNextDelegate:(id *)delPtr delegateQueue:(dispatch_queue_t *)dqPtr forSelector:(SEL)aSelector
{
while (currentNodeIndex < numNodes)
{
OIMGCDMulticastDelegateNode *node = delegateNodes[currentNodeIndex];
currentNodeIndex++;
id nodeDelegate = node.delegate; // snapshot atomic property
#if __has_feature(objc_arc_weak) && !TARGET_OS_IPHONE
if (nodeDelegate == [NSNull null])
nodeDelegate = node.unsafeDelegate;
#endif
if ([nodeDelegate respondsToSelector:aSelector])
{
if (delPtr) *delPtr = nodeDelegate;
if (dqPtr) *dqPtr = node.delegateQueue;
return YES;
}
}
return NO;
}
@end

View File

@ -0,0 +1,64 @@
//
// OIMManager+Connection.h
// OpenIMSDK
//
// Created by x on 2021/2/15.
//
#import "OIMManager.h"
#import "UploadFileCallbackProxy.h"
NS_ASSUME_NONNULL_BEGIN
@interface OIMInitConfig : NSObject
// Device type, default setting is based on userInterfaceIdiom for iPhone/iPad
@property (nonatomic, assign) OIMPlatform platform;
// SDK's API address
@property (nonatomic, copy) NSString *apiAddr;
// SDK's WebSocket address
@property (nonatomic, copy) NSString *wsAddr;
// Default is under Documents/
@property (nonatomic, copy, nullable) NSString *dataDir;
// Log level, default is 6
@property (nonatomic, assign) NSInteger logLevel;
// Compression, default is NO
@property (nonatomic, assign) BOOL compression;
// Log output to local, default is YES
@property (nonatomic, assign) BOOL isLogStandardOutput;
@property (nonatomic, copy, nullable) NSString *logFilePath;
// for log
@property (nonatomic, copy) NSString *systemType;
@end
@interface OIMManager (Connection)
- (BOOL)initSDKWithConfig:(OIMInitConfig *)config
onConnecting:(OIMVoidCallback)onConnecting
onConnectFailure:(OIMFailureCallback)onConnectFailure
onConnectSuccess:(OIMVoidCallback)onConnectSuccess
onKickedOffline:(OIMVoidCallback)onKickedOffline
onUserTokenExpired:(OIMVoidCallback)onUserTokenExpired
onUserTokenInvalid:(OIMStringCallback)onUserTokenInvalid;
- (void)unInitSDK;
- (void)uploadLogsWithProgress:(OIMUploadProgressCallback)onProgress
line:(NSInteger )line
ex:(NSString *)ex
onSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure;
- (void)logs:(NSString * _Nullable)file
line:(NSInteger)line
msgs:(NSString * _Nullable)msgs
err:(NSString * _Nullable)err
keyAndValues:(NSArray * _Nullable)keyAndValues
logLevel:(NSInteger )logLevel;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,94 @@
//
// OIMManager+Connection.m
// OpenIMSDK
//
// Created by x on 2021/2/15.
//
#import "OIMManager+Connection.h"
#import "CallbackProxy.h"
@implementation OIMInitConfig
- (instancetype)init {
self = [super init];
if (self) {
self.platform = [UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad ? iPad : iPhone;
self.dataDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingString:@"/"];
self.logFilePath = self.dataDir;
self.isLogStandardOutput = YES;
self.logLevel = 5;
self.compression = NO;
self.systemType = @"native_iOS";
}
return self;
}
@end
@implementation OIMManager (Connection)
- (BOOL)initSDKWithConfig:(OIMInitConfig *)config
onConnecting:(OIMVoidCallback)onConnecting
onConnectFailure:(OIMFailureCallback)onConnectFailure
onConnectSuccess:(OIMVoidCallback)onConnectSuccess
onKickedOffline:(OIMVoidCallback)onKickedOffline
onUserTokenExpired:(OIMVoidCallback)onUserTokenExpired
onUserTokenInvalid:(OIMStringCallback)onUserTokenInvalid {
[self class].callbacker.connecting = onConnecting;
[self class].callbacker.connectFailure = onConnectFailure;
[self class].callbacker.connectSuccess = onConnectSuccess;
[self class].callbacker.kickedOffline = onKickedOffline;
[self class].callbacker.userTokenExpired = onUserTokenExpired;
[self class].callbacker.userTokenInvalid = onUserTokenInvalid;
NSMutableDictionary *param = [NSMutableDictionary new];
param[@"platformID"] = @(config.platform);
param[@"apiAddr"] = config.apiAddr;
param[@"wsAddr"] = config.wsAddr;
param[@"dataDir"] = config.dataDir;
param[@"logLevel"] = @(config.logLevel);
param[@"isCompression"] = @(config.compression);
param[@"logFilePath"] = config.logFilePath;
param[@"isLogStandardOutput"] = @(config.isLogStandardOutput);
param[@"systemType"] = config.systemType;
return Open_im_sdkInitSDK([self class].callbacker, [self operationId], param.mj_JSONString);
}
- (void)unInitSDK {
Open_im_sdkUnInitSDK([self operationId]);
}
- (void)uploadLogsWithProgress:(OIMUploadProgressCallback)onProgress
line:(NSInteger )line
ex:(NSString *)ex
onSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:onSuccess onFailure:onFailure];
UploadLogsCallbackProxy *progress = [[UploadLogsCallbackProxy alloc] initWithOnProgress:onProgress];
Open_im_sdkUploadLogs(callback, [self operationId], line, ex, progress);
}
- (void)logs:(NSString *)file
line:(NSInteger)line
msgs:(NSString *)msgs
err:(NSString *)err
keyAndValues:(NSArray *)keyAndValues
logLevel:(NSInteger )logLevel {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:^(NSString * _Nullable data) {
} onFailure:^(NSInteger code, NSString * _Nullable msg) {
}];
Open_im_sdkLogs(callback, [self operationId], logLevel, file ?: @"", line, msgs ?: @"", err ?: @"", (keyAndValues ?: @[]).mj_JSONString);
}
@end

View File

@ -0,0 +1,192 @@
//
// OIMManager+Conversation.h
// OpenIMSDK
//
// Created by x on 2022/2/16.
//
#import "OIMManager.h"
#import "OIMConversationInfo.h"
NS_ASSUME_NONNULL_BEGIN
@interface OIMManager (Conversation)
/**
* Get the list of conversations
*/
- (void)getAllConversationListWithOnSuccess:(nullable OIMConversationsInfoCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Get a paginated list of conversations
* @param offset Starting offset
* @param count Number of conversations to fetch
*/
- (void)getConversationListSplitWithOffset:(NSInteger)offset
count:(NSInteger)count
onSuccess:(nullable OIMConversationsInfoCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Get a conversation; it will be automatically created if it doesn't exist
* @param sessionType Type of the conversation, 1 for one-on-one, 2 for group
* @param sourceID User ID for one-on-one or group ID for group
*/
- (void)getOneConversationWithSessionType:(OIMConversationType)sessionType
sourceID:(NSString *)sourceID
onSuccess:(nullable OIMConversationInfoCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Get multiple conversation lists
* @param conversationIDs List of conversation IDs
*/
- (void)getMultipleConversation:(NSArray <NSString *> *)conversationIDs
onSuccess:(nullable OIMConversationsInfoCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
- (NSString *)getConversationIDBySessionType:(OIMConversationType)sessionType
sourceID:(NSString *)sourceID;
/**
* Delete a conversation locally
* @param conversationID Conversation ID
*/
- (void)deleteConversationAndDeleteAllMsg:(NSString *)conversationID
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Clear a conversation both locally and on the server
* @param conversationID Conversation ID
*/
- (void)clearConversationAndDeleteAllMsg:(NSString *)conversationID
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Delete all conversations
*/
- (void)deleteAllConversationFromLocalWithOnSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure __attribute__((deprecated("Use hideAllConversations instead")));
/**
* Set the draft for a conversation
* @param conversationID Conversation ID
* @param draftText Draft text; if it's "", the draft will be deleted
*/
- (void)setConversationDraft:(NSString *)conversationID
draftText:(NSString *)draftText
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Pin or unpin a conversation
* @param conversationID Conversation ID
* @param isPinned If YES, the conversation will be pinned; if NO, it will be unpinned
*/
- (void)pinConversation:(NSString *)conversationID
isPinned:(BOOL)isPinned
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Get the total number of unread messages
*/
- (void)getTotalUnreadMsgCountWithOnSuccess:(nullable OIMNumberCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Set the "do not disturb" status for a conversation
*/
- (void)setConversationRecvMessageOpt:(NSString *)conversationID
status:(OIMReceiveMessageOpt)status
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Set private chat mode, can be used for "self-destructing" messages
*/
- (void)setConversationPrivateChat:(NSString *)conversationID
isPrivate:(BOOL)isPrivate
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Set private chat mode with a self-destruct timer
*/
- (void)setConversationBurnDuration:(NSString *)conversationID
duration:(NSInteger)burnDuration
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Reset the at symbol for a conversation
*/
- (void)resetConversationGroupAtType:(NSString *)conversationID
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Hide a conversation without deleting chat history;
* If new messages arrive, the conversation will reappear.
*/
- (void)hideConversation:(NSString *)conversationID
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
- (void)hideAllConversationsWithOnSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure;
/**
* Clear unread messages
*/
- (void)markConversationMessageAsRead:(NSString *)conversationID
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
- (void)setConversationEx:(NSString *)conversationID
ex:(NSString *)ex
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Search sessions based on session name.
*/
- (void)searchConversation:(NSString *)name
onSuccess:(nullable OIMConversationsInfoCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Typing status for one-on-one chat
*
* @param conversationID Receiver's ID
* @param focus Customized tip message
*/
- (void)changeInputStates:(NSString *)conversationID
focus:(BOOL)focus
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Typing status for one-on-one chat
*
* @param conversationID Conversation's ID
* @param userID User's ID
*/
- (void)getInputstates:(NSString *)conversationID
userID:(NSString *)userID
onSuccess:(nullable OIMInputStatusChangedCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* @param req OIMConversationReq
*/
- (void)setConversation:(NSString *)conversationID
req:(NSDictionary *)req
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,221 @@
//
// OIMManager+Conversation.m
// OpenIMSDK
//
// Created by x on 2022/2/16.
//
#import "OIMManager+Conversation.h"
#import "CallbackProxy.h"
#import "OIMConversationInfo.h"
@implementation OIMManager (Conversation)
- (void)getAllConversationListWithOnSuccess:(OIMConversationsInfoCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:^(NSString * _Nullable data) {
if (onSuccess) {
onSuccess([OIMConversationInfo mj_objectArrayWithKeyValuesArray:data]);
}
} onFailure:onFailure];
Open_im_sdkGetAllConversationList(callback, [self operationId]);
}
- (void)getConversationListSplitWithOffset:(NSInteger)offset
count:(NSInteger)count
onSuccess:(OIMConversationsInfoCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:^(NSString * _Nullable data) {
if (onSuccess) {
onSuccess([OIMConversationInfo mj_objectArrayWithKeyValuesArray:data]);
}
} onFailure:onFailure];
Open_im_sdkGetConversationListSplit(callback, [self operationId], offset, count);
}
- (void)getOneConversationWithSessionType:(OIMConversationType)sessionType
sourceID:(NSString *)sourceID
onSuccess:(OIMConversationInfoCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:^(NSString * _Nullable data) {
if (onSuccess) {
onSuccess([OIMConversationInfo mj_objectWithKeyValues:data]);
}
} onFailure:onFailure];
Open_im_sdkGetOneConversation(callback, [self operationId], (int32_t)sessionType, sourceID);
}
- (NSString *)getConversationIDBySessionType:(OIMConversationType)sessionType
sourceID:(NSString *)sourceID {
return Open_im_sdkGetConversationIDBySessionType([self operationId], sourceID, sessionType);
}
- (void)getMultipleConversation:(NSArray<NSString *> *)conversationIDs
onSuccess:(OIMConversationsInfoCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:^(NSString * _Nullable data) {
if (onSuccess) {
onSuccess([OIMConversationInfo mj_objectArrayWithKeyValuesArray:data]);
}
} onFailure:onFailure];
Open_im_sdkGetMultipleConversation(callback, [self operationId], conversationIDs.mj_JSONString);
}
- (void)deleteConversationAndDeleteAllMsg:(NSString *)conversationID
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:onSuccess onFailure:onFailure];
Open_im_sdkDeleteConversationAndDeleteAllMsg(callback, [self operationId], conversationID);
}
- (void)clearConversationAndDeleteAllMsg:(NSString *)conversationID
onSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:onSuccess onFailure:onFailure];
Open_im_sdkClearConversationAndDeleteAllMsg(callback, [self operationId], conversationID);
}
- (void)deleteAllConversationFromLocalWithOnSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
}
- (void)setConversationDraft:(NSString *)conversationID
draftText:(NSString *)draftText
onSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:onSuccess onFailure:onFailure];
Open_im_sdkSetConversationDraft(callback, [self operationId], conversationID, draftText);
}
- (void)pinConversation:(NSString *)conversationID
isPinned:(BOOL)isPinned
onSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
[self setConversation:conversationID req:@{@"isPinned": @(isPinned)} onSuccess:onSuccess onFailure:onFailure];
}
- (void)getTotalUnreadMsgCountWithOnSuccess:(OIMNumberCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:^(NSString * _Nullable data) {
if (onSuccess) {
onSuccess(data.integerValue);
}
} onFailure:onFailure];
Open_im_sdkGetTotalUnreadMsgCount(callback, [self operationId]);
}
- (void)setConversationRecvMessageOpt:(NSString *)conversationID
status:(OIMReceiveMessageOpt)status
onSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
[self setConversation:conversationID req:@{@"recvMsgOpt": @(status)} onSuccess:onSuccess onFailure:onFailure];
}
- (void)setConversationPrivateChat:(NSString *)conversationID
isPrivate:(BOOL)isPrivate
onSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
[self setConversation:conversationID req:@{@"isPrivateChat": @(isPrivate)} onSuccess:onSuccess onFailure:onFailure];
}
- (void)setConversationBurnDuration:(NSString *)conversationID
duration:(NSInteger)burnDuration
onSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
[self setConversation:conversationID req:@{@"burnDuration": @(burnDuration)} onSuccess:onSuccess onFailure:onFailure];
}
- (void)resetConversationGroupAtType:(NSString *)conversationID
onSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
[self setConversation:conversationID req:@{@"groupAtType": @0} onSuccess:onSuccess onFailure:onFailure];
}
- (void)hideConversation:(NSString *)conversationID
onSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:onSuccess onFailure:onFailure];
Open_im_sdkHideConversation(callback, [self operationId], conversationID);
}
- (void)hideAllConversationsWithOnSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:onSuccess onFailure:onFailure];
Open_im_sdkHideAllConversations(callback, [self operationId]);
}
- (void)markConversationMessageAsRead:(NSString *)conversationID
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:onSuccess onFailure:onFailure];
Open_im_sdkMarkConversationMessageAsRead(callback, [self operationId], conversationID);
}
- (void)setConversationEx:(NSString *)conversationID
ex:(NSString *)ex
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure {
[self setConversation:conversationID req:@{@"ex": ex} onSuccess:onSuccess onFailure:onFailure];
}
- (void)searchConversation:(NSString *)name
onSuccess:(nullable OIMConversationsInfoCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:^(NSString * _Nullable data) {
if (onSuccess) {
onSuccess([OIMConversationInfo mj_objectArrayWithKeyValuesArray:data]);
}
} onFailure:onFailure];
Open_im_sdkSearchConversation(callback, [self operationId], name);
}
- (void)changeInputStates:(NSString *)conversationID
focus:(BOOL)focus
onSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:onSuccess onFailure:onFailure];
Open_im_sdkChangeInputStates(callback, [self operationId], conversationID, focus);
}
- (void)getInputstates:(NSString *)conversationID
userID:(NSString *)userID
onSuccess:(OIMInputStatusChangedCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:^(NSString * _Nullable data) {
if (onSuccess) {
onSuccess(data.mj_JSONObject);
}
} onFailure:onFailure];
Open_im_sdkGetInputStates(callback, [self operationId], conversationID, userID);
}
- (void)setConversation:(NSString *)conversationID
req:(NSDictionary *)req
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:onSuccess onFailure:onFailure];
Open_im_sdkSetConversation(callback, [self operationId], conversationID, req.mj_JSONString);
}
@end

View File

@ -0,0 +1,156 @@
//
// OIMManager+Friend.h
// OpenIMSDK
//
// Created by x on 2022/2/16.
//
#import "OIMManager.h"
#import "OIMUpdateFriendsReq.h"
NS_ASSUME_NONNULL_BEGIN
@interface OIMManager (Friend)
/**
* Add a friend
*
* @param userID User ID of the other person
* @param reqMessage Request message
*/
- (void)addFriend:(NSString *)userID
reqMessage:(NSString * _Nullable)reqMessage
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Get received friend applications, i.e., people who have applied to be friends with me
*/
- (void)getFriendApplicationListAsRecipientWithOnSuccess:(nullable OIMFriendApplicationsCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Friend applications sent by the current user
*/
- (void)getFriendApplicationListAsApplicantWithOnSuccess:(nullable OIMFriendApplicationsCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Accept a friend application from someone
* @param userID User ID
*/
- (void)acceptFriendApplication:(NSString *)userID
handleMsg:(NSString *)msg
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Reject a friend application
*
* @param userID User ID
*/
- (void)refuseFriendApplication:(NSString *)userID
handleMsg:(NSString *)msg
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Add to the blacklist
*
* @param userID User ID
*/
- (void)addToBlackList:(NSString *)userID
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
- (void)addToBlackList:(NSString *)userID
ex:(NSString * _Nullable)ex
onSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure;
/**
* Blacklist
*/
- (void)getBlackListWithOnSuccess:(nullable OIMBlacksInfoCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Remove from the blacklist
*
* @param userID User ID
*/
- (void)removeFromBlackList:(NSString *)userID
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Get related information for a specified list of friends
*
* @param usersID List of user IDs
*/
- (void)getSpecifiedFriendsInfo:(NSArray <NSString *> *)usersID
filterBlack:(BOOL)filterBlack
onSuccess:(nullable OIMFriendsInfoCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Get information for all friends
*/
- (void)getFriendListWithFilterBlack:(BOOL)filterBlack
onSuccess:(nullable OIMFriendsInfoCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
- (void)getFriendListPageWithOffset:(NSInteger)offset
count:(NSInteger)count
filterBlack:(BOOL)filterBlack
onSuccess:(nullable OIMFriendsInfoCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Check if there is a friend relationship, i.e., if the user is in the friend list of the logged-in user. Note: Friendship is a two-way relationship.
* A result of 1 means the user is a friend (and not in the blacklist).
*
* @param usersID User ID list
*/
- (void)checkFriend:(NSArray <NSString *> *)usersID
onSuccess:(nullable OIMSimpleResultsCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Set a friend's remark
*
* @param uid User ID
* @param remark Remark information
*/
- (void)setFriendRemark:(NSString *)uid
remark:(NSString * _Nullable)remark
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Delete a friend; friendship is a two-way relationship, this function only deletes the user's own friend
*
* @param friendUserID Friend's ID
*/
- (void)deleteFriend:(NSString *)friendUserID
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Local friend search
*/
- (void)searchFriends:(OIMSearchFriendsParam *)searchParam
onSuccess:(nullable OIMSearchUsersInfoCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
- (void)setFriendsEx:(NSArray<NSString *> *)friendIDs
ex:(NSString *)ex
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
- (void)updateFriends:(OIMUpdateFriendsReq *)req
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,208 @@
//
// OIMManager+Friend.m
// OpenIMSDK
//
// Created by x on 2022/2/16.
//
#import "OIMManager+Friend.h"
#import "CallbackProxy.h"
@implementation OIMManager (Friend)
- (void)addFriend:(NSString *)userID
reqMessage:(NSString *)reqMessage
onSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:onSuccess onFailure:onFailure];
NSDictionary *param = @{@"toUserID": userID, @"reqMsg": reqMessage ?: @""};
Open_im_sdkAddFriend(callback, [self operationId], param.mj_JSONString);
}
- (void)getFriendApplicationListAsRecipientWithOnSuccess:(OIMFriendApplicationsCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:^(NSString * _Nullable data) {
if (onSuccess) {
onSuccess([OIMFriendApplication mj_objectArrayWithKeyValuesArray:data]);
}
} onFailure:onFailure];
Open_im_sdkGetFriendApplicationListAsRecipient(callback, [self operationId]);
}
- (void)getFriendApplicationListAsApplicantWithOnSuccess:(OIMFriendApplicationsCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:^(NSString * _Nullable data) {
if (onSuccess) {
onSuccess([OIMFriendApplication mj_objectArrayWithKeyValuesArray:data]);
}
} onFailure:onFailure];
Open_im_sdkGetFriendApplicationListAsApplicant(callback, [self operationId]);
}
- (void)acceptFriendApplication:(NSString *)userID
handleMsg:(NSString *)msg
onSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:onSuccess onFailure:onFailure];
NSDictionary *param = @{@"toUserID": userID, @"handleMsg": msg ?: @""};
Open_im_sdkAcceptFriendApplication(callback, [self operationId], param.mj_JSONString);
}
- (void)refuseFriendApplication:(NSString *)userID
handleMsg:(NSString *)msg
onSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:onSuccess onFailure:onFailure];
NSDictionary *param = @{@"toUserID": userID, @"handleMsg": msg ?: @""};
Open_im_sdkRefuseFriendApplication(callback, [self operationId], param.mj_JSONString);
}
- (void)addToBlackList:(NSString *)userID
onSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
[self addToBlackList:userID ex:nil onSuccess:onSuccess onFailure:onFailure];
}
- (void)addToBlackList:(NSString *)userID
ex:(NSString *)ex
onSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:onSuccess onFailure:onFailure];
Open_im_sdkAddBlack(callback, [self operationId], userID, ex);
}
- (void)getBlackListWithOnSuccess:(OIMBlacksInfoCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:^(NSString * _Nullable data) {
if (onSuccess) {
onSuccess([OIMBlackInfo mj_objectArrayWithKeyValuesArray:data]);
}
} onFailure:onFailure];
Open_im_sdkGetBlackList(callback, [self operationId]);
}
- (void)removeFromBlackList:(NSString *)userID
onSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:onSuccess onFailure:onFailure];
Open_im_sdkRemoveBlack(callback, [self operationId], userID);
}
- (void)getSpecifiedFriendsInfo:(NSArray <NSString *> *)usersID
filterBlack:(BOOL)filterBlack
onSuccess:(nullable OIMFriendsInfoCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:^(NSString * _Nullable data) {
if (onSuccess) {
onSuccess([OIMFriendInfo mj_objectArrayWithKeyValuesArray:data]);
}
} onFailure:onFailure];
Open_im_sdkGetSpecifiedFriendsInfo(callback, [self operationId], usersID.mj_JSONString, filterBlack);
}
- (void)getFriendListWithFilterBlack:(BOOL)filterBlack
onSuccess:(nullable OIMFriendsInfoCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:^(NSString * _Nullable data) {
if (onSuccess) {
onSuccess([OIMFriendInfo mj_objectArrayWithKeyValuesArray:data]);
}
} onFailure:onFailure];
Open_im_sdkGetFriendList(callback, [self operationId], filterBlack);
}
- (void)getFriendListPageWithOffset:(NSInteger)offset
count:(NSInteger)count
filterBlack:(BOOL)filterBlack
onSuccess:(OIMFriendsInfoCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:^(NSString * _Nullable data) {
if (onSuccess) {
onSuccess([OIMFriendInfo mj_objectArrayWithKeyValuesArray:data]);
}
} onFailure:onFailure];
Open_im_sdkGetFriendListPage(callback, [self operationId], (int32_t)offset, (int32_t)count, filterBlack);
}
- (void)checkFriend:(NSArray<NSString *> *)usersID
onSuccess:(OIMSimpleResultsCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:^(NSString * _Nullable data) {
if (onSuccess) {
onSuccess([OIMSimpleResultInfo mj_objectArrayWithKeyValuesArray:data]);
}
} onFailure:onFailure];
Open_im_sdkCheckFriend(callback, [self operationId], usersID.mj_JSONString);
}
- (void)setFriendRemark:(NSString *)userID
remark:(NSString *)remark
onSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:onSuccess onFailure:onFailure];
OIMUpdateFriendsReq *req = [OIMUpdateFriendsReq new];
req.friendUserIDs = @[userID];
req.remark = remark;
[self updateFriends:req onSuccess:onSuccess onFailure:onFailure];
}
- (void)deleteFriend:(NSString *)friendUserID
onSuccess:(OIMSuccessCallback)onSuccess onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:onSuccess onFailure:onFailure];
Open_im_sdkDeleteFriend(callback, [self operationId], friendUserID);
}
- (void)searchFriends:(OIMSearchFriendsParam *)searchParam
onSuccess:(nullable OIMSearchUsersInfoCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure {
assert(searchParam.isSearchRemark || searchParam.isSearchNickname || searchParam.isSearchUserID);
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:^(NSString * _Nullable data) {
if (onSuccess) {
onSuccess([OIMSearchFriendsInfo mj_objectArrayWithKeyValuesArray:data]);
}
} onFailure:onFailure];
Open_im_sdkSearchFriends(callback, [self operationId], searchParam.mj_JSONString);
}
- (void)setFriendsEx:(NSArray<NSString *> *)friendIDs
ex:(NSString *)ex
onSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:onSuccess onFailure:onFailure];
OIMUpdateFriendsReq *req = [OIMUpdateFriendsReq new];
req.friendUserIDs = friendIDs;
req.ex = ex;
[self updateFriends:req onSuccess:onSuccess onFailure:onFailure];
}
- (void)updateFriends:(OIMUpdateFriendsReq *)req
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:onSuccess onFailure:onFailure];
Open_im_sdkUpdateFriends(callback, [self operationId], req.mj_JSONString);
}
@end

View File

@ -0,0 +1,317 @@
//
// OIMManager+Group.h
// OpenIMSDK
//
// Created by x on 2022/2/16.
//
#import "OIMManager.h"
NS_ASSUME_NONNULL_BEGIN
@interface OIMManager (Group)
/**
* Create a group
*/
- (void)createGroup:(OIMGroupCreateInfo *)groupBaseInfo
onSuccess:(nullable OIMGroupInfoCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Apply to join a group
*
* @param groupID Group ID
* @param reqMsg Request message for joining the group
* @param joinSource Method of joining
*/
- (void)joinGroup:(NSString *)groupID
reqMsg:(NSString * _Nullable)reqMsg
joinSource:(OIMJoinType)joinSource
onSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure;
- (void)joinGroup:(NSString *)groupID
reqMsg:(NSString *)reqMsg
joinSource:(OIMJoinType)joinSource
ex:(NSString * _Nullable)ex
onSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure;
/**
* Quit a group
*/
- (void)quitGroup:(NSString *)groupID
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Get the list of joined groups
*/
- (void)getJoinedGroupListWithOnSuccess:(nullable OIMGroupsInfoCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
- (void)getJoinedGroupListPageWithOffset:(NSInteger)offset
count:(NSInteger)count
onSuccess:(nullable OIMGroupsInfoCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Batch get group information
*
* @param groupsID Group ID collection
*/
- (void)getSpecifiedGroupsInfo:(NSArray <NSString *> *)groupsID
onSuccess:(nullable OIMGroupsInfoCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Set or update group information
*/
- (void)setGroupInfo:(OIMGroupInfo *)groupInfo
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
- (void)setGroupInfoDictionary:(NSDictionary *)groupInfo
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Get group members
*
* @param groupID Group ID
* @param filter Member filter, 0 for no filter, 1 for group creator, 2 for administrator; default value is 0
* @param offset Starting offset
* @param count Member count
*/
- (void)getGroupMemberList:(NSString *)groupID
filter:(OIMGroupMemberFilter)filter
offset:(NSInteger)offset
count:(NSInteger)count
onSuccess:(nullable OIMGroupMembersInfoCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Get a list of specified group members
*
* @param groupID Group ID
* @param usersID Group member IDs
*/
- (void)getSpecifiedGroupMembersInfo:(NSString *)groupID
usersID:(NSArray <NSString *> *)usersID
onSuccess:(nullable OIMGroupMembersInfoCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Remove members from a group
*
* @param groupID Group ID
* @param reason Reason for removal
* @param usersID List of user IDs to be removed from the group
*/
- (void)kickGroupMember:(NSString *)groupID
reason:(NSString * _Nullable)reason
usersID:(NSArray <NSString *> *)usersID
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Transfer group ownership, only the group owner can perform this action
*
* @param groupID Group ID
* @param userID New group owner's user ID
*/
- (void)transferGroupOwner:(NSString *)groupID
newOwner:(NSString *)userID
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Invite certain people to join a group; all group members can perform this action
*
* @param groupID Group ID
* @param usersID List of user IDs to be invited
* @param reason Invitation message
*/
- (void)inviteUserToGroup:(NSString *)groupID
reason:(NSString *)reason
usersID:(NSArray <NSString *> *)usersID
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Get a list of group member applications received by administrators or group owners
*/
- (void)getGroupApplicationListAsRecipientWithOnSuccess:(nullable OIMGroupsApplicationCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Group applications sent by the current user
*/
- (void)getGroupApplicationListAsApplicantWithOnSuccess:(nullable OIMGroupsApplicationCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Accept someone's application to join a group as an administrator or group owner
*
* @param groupID Group ID
* @param fromUserID User ID of the user applying to join the group
* @param handleMsg Handling message
*/
- (void)acceptGroupApplication:(NSString *)groupID
fromUserId:(NSString *)fromUserID
handleMsg:(NSString * _Nullable)handleMsg
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/*
* Reject someone's application to join a group as an administrator or group owner
*
* @param groupId Group ID
* @param fromUserID User ID of the user applying to join the group
* @param handleMsg Handling message
*/
- (void)refuseGroupApplication:(NSString *)groupID
fromUserId:(NSString *)fromUserID
handleMsg:(NSString * _Nullable)handleMsg
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Disband a group
* Disband a group
*
* @param groupID Group ID
*/
- (void)dismissGroup:(NSString *)groupID
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Mute or unmute a group member, mutedSeconds is set to 0 for unmuting
*/
- (void)changeGroupMemberMute:(NSString *)groupID
userID:(NSString *)userID
mutedSeconds:(NSInteger)mutedSeconds
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Mute or unmute a group
*/
- (void)changeGroupMute:(NSString *)groupID
isMute:(BOOL)isMute
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Search for groups by group name or group ID
*/
- (void)searchGroups:(OIMSearchGroupParam *)searchParam
onSuccess:(nullable OIMGroupsInfoCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Set group member nickname
*/
- (void)setGroupMemberNickname:(NSString *)groupID
userID:(NSString *)userID
groupNickname:(NSString * _Nullable)groupNickname
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Set group member role level
*/
- (void)setGroupMemberRoleLevel:(NSString *)groupID
userID:(NSString *)userID
roleLevel:(OIMGroupMemberRole)roleLevel
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Set group member's info
* @param groupMemberInfo OIMSetGroupMemberInfo
*/
- (void)setGroupMemberInfo:(NSDictionary *)groupMemberInfo
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Get the list of group members based on join time
* @param groupID Group ID
* @param joinTimeBegin Start time for joining
* @param joinTimeEnd End time for joining
* @param offset Starting index
* @param count Total count
* @param filterUserIDList List of user IDs to filter
*/
- (void)getGroupMemberListByJoinTimeFilter:(NSString *)groupID
offset:(NSInteger)offset
count:(NSInteger)count
joinTimeBegin:(NSInteger)joinTimeBegin
joinTimeEnd:(NSInteger)joinTimeEnd
filterUserIDList:(NSArray <NSString *> *)filterUserIDList
onSuccess:(nullable OIMGroupMembersInfoCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Set group verification option for joining
* @param groupID Group ID
* @param needVerification Joining settings
*/
- (void)setGroupVerification:(NSString *)groupID
needVerification:(OIMGroupVerificationType)needVerification
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Get the list of managers and owners
* @param groupID Group ID
*/
- (void)getGroupMemberOwnerAndAdmin:(NSString *)groupID
onSuccess:(nullable OIMGroupMembersInfoCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Determine whether group members can add each other as friends
* @param groupID Group ID
* @param rule 0: Default behavior, 1: Not allowed
*/
- (void)setGroupApplyMemberFriend:(NSString *)groupID
rule:(int32_t)rule
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* View group member information
* @param groupID Group ID
* @param rule 0: Default behavior, 1: Not allowed
*/
- (void)setGroupLookMemberInfo:(NSString *)groupID
rule:(int32_t)rule
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Search group members
*/
- (void)searchGroupMembers:(OIMSearchGroupMembersParam *)searchParam
onSuccess:(nullable OIMGroupMembersInfoCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Check if the user has joined the group
*/
- (void)isJoinedGroup:(NSString *)groupID
onSuccess:(nullable OIMBoolCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
- (void)getUsersInGroup:(NSString *)groupID
userIDs:(NSArray<NSString *> *)userIDs
onSuccess:(nullable OIMStringArrayCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,365 @@
//
// OIMManager+Group.m
// OpenIMSDK
//
// Created by x on 2022/2/16.
//
#import "OIMManager+Group.h"
#import "CallbackProxy.h"
@implementation OIMManager (Group)
- (void)createGroup:(OIMGroupCreateInfo *)groupCreateInfo
onSuccess:(OIMGroupInfoCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:^(NSString * _Nullable data) {
if (onSuccess) {
onSuccess([OIMGroupInfo mj_objectWithKeyValues:data]);
}
} onFailure:onFailure];
Open_im_sdkCreateGroup(callback, [self operationId], groupCreateInfo.mj_JSONString);
}
- (void)joinGroup:(NSString *)groupID
reqMsg:(NSString *)reqMsg
joinSource:(OIMJoinType)joinSource
onSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:onSuccess onFailure:onFailure];
Open_im_sdkJoinGroup(callback, [self operationId], groupID, reqMsg ?: @"", joinSource, nil);
}
- (void)joinGroup:(NSString *)groupID
reqMsg:(NSString *)reqMsg
joinSource:(OIMJoinType)joinSource
ex:(NSString *)ex
onSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:onSuccess onFailure:onFailure];
Open_im_sdkJoinGroup(callback, [self operationId], groupID, reqMsg ?: @"", joinSource, ex);
}
- (void)quitGroup:(NSString *)groupID
onSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:onSuccess onFailure:onFailure];
Open_im_sdkQuitGroup(callback, [self operationId], groupID);
}
- (void)getJoinedGroupListWithOnSuccess:(OIMGroupsInfoCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:^(NSString * _Nullable data) {
if (onSuccess) {
onSuccess([OIMGroupInfo mj_objectArrayWithKeyValuesArray:data]);
}
} onFailure:onFailure];
Open_im_sdkGetJoinedGroupList(callback, [self operationId]);
}
- (void)getJoinedGroupListPageWithOffset:(NSInteger)offset
count:(NSInteger)count
onSuccess:(OIMGroupsInfoCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:^(NSString * _Nullable data) {
if (onSuccess) {
onSuccess([OIMGroupInfo mj_objectArrayWithKeyValuesArray:data]);
}
} onFailure:onFailure];
Open_im_sdkGetJoinedGroupListPage(callback, [self operationId], (int32_t)offset, (int32_t)count);
}
- (void)getSpecifiedGroupsInfo:(NSArray <NSString *> *)groupsID
onSuccess:(nullable OIMGroupsInfoCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:^(NSString * _Nullable data) {
if (onSuccess) {
onSuccess([OIMGroupInfo mj_objectArrayWithKeyValuesArray:data]);
}
} onFailure:onFailure];
Open_im_sdkGetSpecifiedGroupsInfo(callback, [self operationId], groupsID.mj_JSONString);
}
- (void)setGroupInfo:(OIMGroupInfo *)groupInfo
onSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:onSuccess onFailure:onFailure];
Open_im_sdkSetGroupInfo(callback, [self operationId], groupInfo.mj_JSONString);
}
- (void)setGroupInfoDictionary:(NSDictionary *)groupInfo
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:onSuccess onFailure:onFailure];
Open_im_sdkSetGroupInfo(callback, [self operationId], groupInfo.mj_JSONString);
}
- (void)getGroupMemberList:(NSString *)groupID
filter:(OIMGroupMemberFilter)filter
offset:(NSInteger)offset
count:(NSInteger)count
onSuccess:(OIMGroupMembersInfoCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:^(NSString * _Nullable data) {
if (onSuccess) {
onSuccess([OIMGroupMemberInfo mj_objectArrayWithKeyValuesArray:data]);
}
} onFailure:onFailure];
Open_im_sdkGetGroupMemberList(callback, [self operationId], groupID, (int32_t)filter, (int32_t)offset, (int32_t)count);
}
- (void)getSpecifiedGroupMembersInfo:(NSString *)groupID
usersID:(NSArray <NSString *> *)usersID
onSuccess:(nullable OIMGroupMembersInfoCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:^(NSString * _Nullable data) {
if (onSuccess) {
onSuccess([OIMGroupMemberInfo mj_objectArrayWithKeyValuesArray:data]);
}
} onFailure:onFailure];
Open_im_sdkGetSpecifiedGroupMembersInfo(callback, [self operationId], groupID, usersID.mj_JSONString);
}
- (void)kickGroupMember:(NSString *)groupID
reason:(NSString *)reason
usersID:(NSArray <NSString *> *)usersID
onSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:onSuccess onFailure:onFailure];
Open_im_sdkKickGroupMember(callback, [self operationId], groupID, reason ?: @"", usersID.mj_JSONString);
}
- (void)transferGroupOwner:(NSString *)groupID
newOwner:(NSString *)userID
onSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:onSuccess onFailure:onFailure];
Open_im_sdkTransferGroupOwner(callback, [self operationId], groupID, userID);
}
- (void)inviteUserToGroup:(NSString *)groupID
reason:(NSString *)reason
usersID:(NSArray <NSString *> *)usersID
onSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:onSuccess onFailure:onFailure];
Open_im_sdkInviteUserToGroup(callback, [self operationId], groupID, reason ?: @"", usersID.mj_JSONString);
}
- (void)getGroupApplicationListAsRecipientWithOnSuccess:(OIMGroupsApplicationCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:^(NSString * _Nullable data) {
if (onSuccess) {
onSuccess([OIMGroupApplicationInfo mj_objectArrayWithKeyValuesArray:data]);
}
} onFailure:onFailure];
Open_im_sdkGetGroupApplicationListAsRecipient(callback, [self operationId]);
}
- (void)getGroupApplicationListAsApplicantWithOnSuccess:(OIMGroupsApplicationCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:^(NSString * _Nullable data) {
if (onSuccess) {
onSuccess([OIMGroupApplicationInfo mj_objectArrayWithKeyValuesArray:data]);
}
} onFailure:onFailure];
Open_im_sdkGetGroupApplicationListAsApplicant(callback, [self operationId]);
}
- (void)acceptGroupApplication:(NSString *)groupID
fromUserId:(NSString *)fromUserID
handleMsg:(NSString *)handleMsg
onSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:onSuccess onFailure:onFailure];
Open_im_sdkAcceptGroupApplication(callback, [self operationId], groupID, fromUserID, handleMsg ?: @"");
}
- (void)refuseGroupApplication:(NSString *)groupID
fromUserId:(NSString *)fromUserID
handleMsg:(NSString *)handleMsg
onSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:onSuccess onFailure:onFailure];
Open_im_sdkRefuseGroupApplication(callback, [self operationId], groupID, fromUserID, handleMsg ?: @"");
}
- (void)dismissGroup:(NSString *)groupID
onSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:onSuccess onFailure:onFailure];
Open_im_sdkDismissGroup(callback, [self operationId], groupID);
}
- (void)changeGroupMemberMute:(NSString *)groupID
userID:(NSString *)userID
mutedSeconds:(NSInteger)mutedSeconds
onSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:onSuccess onFailure:onFailure];
Open_im_sdkChangeGroupMemberMute(callback, [self operationId], groupID, userID, mutedSeconds);
}
- (void)changeGroupMute:(NSString *)groupID
isMute:(BOOL)isMute
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:onSuccess onFailure:onFailure];
Open_im_sdkChangeGroupMute(callback, [self operationId], groupID, isMute);
}
- (void)searchGroups:(OIMSearchGroupParam *)searchParam
onSuccess:(OIMGroupsInfoCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:^(NSString * _Nullable data) {
if (onSuccess) {
onSuccess([OIMGroupInfo mj_objectArrayWithKeyValuesArray:data]);
}
} onFailure:onFailure];
Open_im_sdkSearchGroups(callback, [self operationId], searchParam.mj_JSONString);
}
- (void)setGroupMemberNickname:(NSString *)groupID
userID:(NSString *)userID
groupNickname:(NSString *)groupNickname
onSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
[self setGroupMemberInfo:@{@"groupID": groupID, @"userID": userID, @"nickname": groupNickname} onSuccess:onSuccess onFailure:onFailure];
}
- (void)setGroupMemberRoleLevel:(NSString *)groupID
userID:(NSString *)userID
roleLevel:(OIMGroupMemberRole)roleLevel
onSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
[self setGroupMemberInfo:@{@"groupID": groupID, @"userID": userID, @"roleLevel": @(roleLevel)} onSuccess:onSuccess onFailure:onFailure];
}
- (void)setGroupMemberInfo:(NSDictionary *)groupMemberInfo
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:onSuccess onFailure:onFailure];
Open_im_sdkSetGroupMemberInfo(callback, [self operationId], groupMemberInfo.mj_JSONString);
}
- (void)getGroupMemberListByJoinTimeFilter:(NSString *)groupID
offset:(NSInteger)offset
count:(NSInteger)count
joinTimeBegin:(NSInteger)joinTimeBegin
joinTimeEnd:(NSInteger)joinTimeEnd
filterUserIDList:(NSArray <NSString *> *)filterUserIDList
onSuccess:(OIMGroupMembersInfoCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:^(NSString * _Nullable data) {
if (onSuccess) {
onSuccess([OIMGroupMemberInfo mj_objectArrayWithKeyValuesArray:data]);
}
} onFailure:onFailure];
Open_im_sdkGetGroupMemberListByJoinTimeFilter(callback, [self operationId], groupID, (int32_t)offset, (int32_t)count, joinTimeBegin, joinTimeEnd, filterUserIDList.mj_JSONString);
}
- (void)setGroupVerification:(NSString *)groupID
needVerification:(OIMGroupVerificationType)needVerification
onSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
[self setGroupInfoDictionary:@{@"groupID": groupID, @"needVerification": @(needVerification)} onSuccess:onSuccess onFailure:onFailure];
}
- (void)getGroupMemberOwnerAndAdmin:(NSString *)groupID
onSuccess:(OIMGroupMembersInfoCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:^(NSString * _Nullable data) {
if (onSuccess) {
onSuccess([OIMGroupMemberInfo mj_objectArrayWithKeyValuesArray:data]);
}
} onFailure:onFailure];
Open_im_sdkGetGroupMemberOwnerAndAdmin(callback, [self operationId], groupID);
}
- (void)setGroupApplyMemberFriend:(NSString *)groupID
rule:(int32_t)rule
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure {
[self setGroupInfoDictionary:@{@"groupID": groupID, @"applyMemberFriend": @(rule)} onSuccess:onSuccess onFailure:onFailure];
}
- (void)setGroupLookMemberInfo:(NSString *)groupID
rule:(int32_t)rule
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure {
[self setGroupInfoDictionary:@{@"groupID": groupID, @"lookMemberInfo": @(rule)} onSuccess:onSuccess onFailure:onFailure];
}
- (void)searchGroupMembers:(OIMSearchParam *)searchParam
onSuccess:(OIMGroupMembersInfoCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:^(NSString * _Nullable data) {
if (onSuccess) {
onSuccess([OIMGroupMemberInfo mj_objectArrayWithKeyValuesArray:data]);
}
} onFailure:onFailure];
Open_im_sdkSearchGroupMembers(callback, [self operationId], searchParam.mj_JSONString);
}
- (void)isJoinedGroup:(NSString *)groupID
onSuccess:(OIMBoolCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:^(NSString * _Nullable data) {
if (onSuccess) {
onSuccess([data isEqualToString:@"true"]);
}
} onFailure:onFailure];
Open_im_sdkIsJoinGroup(callback, [self operationId], groupID);
}
- (void)getUsersInGroup:(NSString *)groupID
userIDs:(NSArray<NSString *> *)userIDs
onSuccess:(nullable OIMStringArrayCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:^(NSString * _Nullable data) {
if (onSuccess) {
NSArray<NSString *> *users = data.mj_JSONObject;
onSuccess(nil, users);
}
} onFailure:onFailure];
Open_im_sdkGetUsersInGroup(callback, [self operationId], groupID, userIDs.mj_JSONString);
}
@end

View File

@ -0,0 +1,43 @@
//
// OIMManager+Login.h
// OpenIMSDK
//
// Created by x on 2022/2/16.
//
#import "OIMManager.h"
NS_ASSUME_NONNULL_BEGIN
@interface OIMManager (Login)
#pragma mark -
#pragma mark - Login
/**
* Log in
*
* @param userID User ID
* The UID is obtained from your own business server.
* @param token User token
* The token needs to be obtained by the business server from the OpenIM server.
*/
- (void)login:(NSString *)userID
token:(NSString *)token
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Get login status
*/
- (OIMLoginStatus)getLoginStatus;
/**
* Log out
*/
- (void)logoutWithOnSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,42 @@
//
// OIMManager+Login.m
// OpenIMSDK
//
// Created by x on 2022/2/16.
//
#import "OIMManager+Login.h"
#import "CallbackProxy.h"
@implementation OIMManager (Login)
- (void)login:(NSString *)userID
token:(NSString *)token
onSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:^(NSString * _Nullable data) {
self.token = token;
if (onSuccess) {
onSuccess(data);
}
} onFailure:onFailure];
[[self class].callbacker setListener];
Open_im_sdkLogin(callback, [self operationId], userID, token);
}
- (OIMLoginStatus)getLoginStatus {
return Open_im_sdkGetLoginStatus([self operationId]);
}
- (void)logoutWithOnSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:onSuccess onFailure:onFailure];
Open_im_sdkLogout(callback, [self operationId]);
}
@end

View File

@ -0,0 +1,481 @@
//
// OIMManager+Message.h
// OpenIMSDK
//
// Created by x on 2022/2/16.
//
#import "OIMManager.h"
#import "UploadFileCallbackProxy.h"
NS_ASSUME_NONNULL_BEGIN
@interface OIMMessageInfo (extension)
/*
* Whether the message is sent by self.
*/
- (BOOL)isSelf;
/*
* Create a text message.
*
* @param text Content
*/
+ (OIMMessageInfo *)createTextMessage:(NSString *)text;
/**
* Complement the use of createTextAtMessage, insert the "@all" flag at a specified position.
*/
+ (OIMAtInfo *)createAtAllFlag:(NSString *)displayText;
+ (NSString *)getAtAllTag;
/*
* Create an @ text message.
*
* @param text Content
* @param atUsersID User IDs to mention
* @param atUsersInfo User information in the group
* @param message Message to reference
*/
+ (OIMMessageInfo *)createTextAtMessage:(NSString *)text
atUsersID:(NSArray<NSString *> *)atUsersID
atUsersInfo:(NSArray<OIMAtInfo *> *)atUsersInfo
message:(OIMMessageInfo * _Nullable)message;
/*
* Create an @ all members text message.
*
* @param text Content
* @param displayText Display text, e.g., "@All members"
* @param message Message to reference
*/
+ (OIMMessageInfo *)createTextAtAllMessage:(NSString *)text
displayText:(NSString * _Nullable)displayText
message:(OIMMessageInfo * _Nullable)message;
/*
* Create an image message. (If you provided a data cache path during initSDK, you need to copy the image to that path. For example, if the path is "A", you should copy the image to "A/pic/a.png", and the imagePath should be "/pic/a.png").
*
* @param imagePath Relative path
*/
+ (OIMMessageInfo *)createImageMessage:(NSString *)imagePath;
/*
* Create an image message.
*
* @param imagePath Absolute path
*/
+ (OIMMessageInfo *)createImageMessageFromFullPath:(NSString *)imagePath;
/*
* Create an audio message. For example: upload your own audio file and then use the returned URL to send the message.
*
*/
+ (OIMMessageInfo *)createImageMessageByURL:(NSString *)sourcePath
sourcePicture:(OIMPictureInfo *)source
bigPicture:(OIMPictureInfo *)big
snapshotPicture:(OIMPictureInfo *)snapshot;
/*
* Create a sound message. (If you provided a data cache path during initSDK, you need to copy the sound file to that path. For example, if the path is "A", you should copy the sound file to "A/voice/a.m4c", and the soundPath should be "/voice/a.m4c").
*
* @param soundPath Relative path
* @param duration Duration
*/
+ (OIMMessageInfo *)createSoundMessage:(NSString *)soundPath
duration:(NSInteger)duration;
/*
* Create a sound message.
*
* @param soundPath Absolute path
* @param duration Duration
*/
+ (OIMMessageInfo *)createSoundMessageFromFullPath:(NSString *)soundPath
duration:(NSInteger)duration;
/*
* Create an audio message. For example: upload your own audio file and then use the returned URL to send the message.
*
*/
+ (OIMMessageInfo *)createSoundMessageByURL:(NSString *)fileURL
duration:(NSInteger)duration
size:(NSInteger)size;
/*
* Create a video message. (If you provided a data cache path during initSDK, you need to copy the video file to that path. For example, if the path is "A", you should copy the video file to "A/video/a.mp4", and the videoPath should be "/video/a.mp4").
*
* @param videoPath Relative video path
* @param videoType MIME type
* @param duration Duration
* @param snapshotPath Relative path of the snapshot
*/
+ (OIMMessageInfo *)createVideoMessage:(NSString *)videoPath
videoType:(NSString *)videoType
duration:(NSInteger)duration
snapshotPath:(NSString *)snapshotPath;
/*
* Create a video message.
*
* @param videoPath Absolute video path
* @param videoType MIME type
* @param duration Duration
* @param snapshotPath Absolute snapshot path
*/
+ (OIMMessageInfo *)createVideoMessageFromFullPath:(NSString *)videoPath
videoType:(NSString *)videoType
duration:(NSInteger)duration
snapshotPath:(NSString *)snapshotPath;
/*
* Create a video message. For example: upload your own video file and then use the returned URL to send the message.
*
*/
+ (OIMMessageInfo *)createVideoMessageByURL:(NSString *)fileURL
videoType:(NSString * _Nullable)videoType
duration:(NSInteger)duration
size:(NSInteger)size
snapshot:(NSString * _Nullable)snapshotURL;
/*
* Create a file message. (If you provided a data cache path during initSDK, you need to copy the file to that path. For example, if the path is "A", you should copy the file to "A/file/a.txt", and the filePath should be "/file/a.txt").
*
* @param filePath Relative path
* @param fileName File name
*/
+ (OIMMessageInfo *)createFileMessage:(NSString *)filePath
fileName:(NSString *)fileName;
/*
* Create a file message.
* (If you provided a data cache path during initSDK, you need to copy the file to that path. For example, if the path is "A", you should copy the file to "A/file/a.txt", and the filePath should be "/file/a.txt").
*
* @param filePath Absolute path
* @param fileName File name
*
*/
+ (OIMMessageInfo *)createFileMessageFromFullPath:(NSString *)filePath
fileName:(NSString *)fileName;
/*
* Create a file message. For example: upload your own file and then use the returned URL to send the message.
*
*/
+ (OIMMessageInfo *)createFileMessageByURL:(NSString *)fileURL
fileName:(NSString * _Nullable)fileName
size:(NSInteger)size;
/*
* Create a merged message.
*
* @param title Title
* @param summaryList Summaries
* @param messageList Message list
*/
+ (OIMMessageInfo *)createMergeMessage:(NSArray <OIMMessageInfo *> *)messages
title:(NSString *)title
summaryList:(NSArray <NSString *> *)summaries;
/*
* Create a forwarded message.
*
*/
+ (OIMMessageInfo *)createForwardMessage:(OIMMessageInfo *)message;
/*
* Create a location message.
*
* @param description Description message
* @param latitude Latitude
* @param longitude Longitude
*/
+ (OIMMessageInfo *)createLocationMessage:(NSString *)description
latitude:(double)latitude
longitude:(double)longitude;
/*
* Create a quoted message.
*
* @param text Content
* @param message Message being quoted
*
*/
+ (OIMMessageInfo *)createQuoteMessage:(NSString *)text
message:(OIMMessageInfo *)message;
/*
* Create a business card message.
*
* @param content String
*/
+ (OIMMessageInfo *)createCardMessage:(OIMCardElem *)card;
/*
* Create a custom message.
*
* @param data JSON String
* @param extension JSON String
* @param description Description
*/
+ (OIMMessageInfo *)createCustomMessage:(NSString *)data
extension:(NSString * _Nullable)extension
description:(NSString * _Nullable)description;
/*
* Create an animated sticker message.
*
*/
+ (OIMMessageInfo *)createFaceMessageWithIndex:(NSInteger)index
data:(NSString *)dataStr;
/*
* Create an advanced message.
*
*/
+ (OIMMessageInfo *)createAdvancedTextMessage:(NSString *)text
messageEntityList:(NSArray <OIMMessageEntity *> *)messageEntityList;
/*
* Create an advanced quoted message.
*
*/
+ (OIMMessageInfo *)createAdvancedQuoteMessage:(NSString *)text
message:(OIMMessageInfo *)message
messageEntityList:(NSArray <OIMMessageEntity *> *)messageEntityList;
@end
@interface OIMManager (Message)
/**
* Send a message
*
* @param message The message body created with Create...Message methods (OIMMessageInfo)
* @param recvID User ID for one-on-one chat, or an empty string for group chat
* @param groupID Group ID for group chat, or an empty string for one-on-one chat
* @param offlinePushInfo Offline push information for the message (OIMOfflinePushInfo)
* @param isOnlineOnly Whether to send only online messages.
*/
- (void)sendMessage:(OIMMessageInfo *)message
recvID:(NSString * _Nullable)recvID
groupID:(NSString * _Nullable)groupID
isOnlineOnly:(BOOL)isOnlineOnly
offlinePushInfo:(OIMOfflinePushInfo * _Nullable)offlinePushInfo
onSuccess:(nullable OIMMessageInfoCallback)onSuccess
onProgress:(nullable OIMNumberCallback)onProgress
onFailure:(nullable OIMFailureCallback)onFailure;
- (void)sendMessage:(OIMMessageInfo *)message
recvID:(NSString * _Nullable)recvID
groupID:(NSString * _Nullable)groupID
offlinePushInfo:(OIMOfflinePushInfo * _Nullable)offlinePushInfo
onSuccess:(nullable OIMMessageInfoCallback)onSuccess
onProgress:(nullable OIMNumberCallback)onProgress
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Send a message without uploading multimedia files through the built-in SDK Object Storage Service (OSS)
*
* @param message The message body created with Create...Message methods (OIMMessageInfo)
* @param recvID User ID for one-on-one chat, or an empty string for group chat
* @param groupID Group ID for group chat, or an empty string for one-on-one chat
* @param offlinePushInfo Offline push information for the message (OIMOfflinePushInfo)
* @param isOnlineOnly Whether to send only online messages.
*/
- (void)sendMessageNotOss:(OIMMessageInfo *)message
recvID:(NSString * _Nullable)recvID
groupID:(NSString * _Nullable)groupID
isOnlineOnly:(BOOL)isOnlineOnly
offlinePushInfo:(OIMOfflinePushInfo * _Nullable)offlinePushInfo
onSuccess:(nullable OIMMessageInfoCallback)onSuccess
onProgress:(nullable OIMNumberCallback)onProgress
onFailure:(nullable OIMFailureCallback)onFailure;
- (void)sendMessageNotOss:(OIMMessageInfo *)message
recvID:(NSString * _Nullable)recvID
groupID:(NSString * _Nullable)groupID
offlinePushInfo:(OIMOfflinePushInfo *)offlinePushInfo
onSuccess:(nullable OIMMessageInfoCallback)onSuccess
onProgress:(nullable OIMNumberCallback)onProgress
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Revoke a message
*
* @param conversationID Conversation ID
* @param clientMsgID Message ID
*/
- (void)revokeMessage:(NSString *)conversationID
clientMsgID:(NSString *)clientMsgID
onSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure;
/**
* Typing status for one-on-one chat
*
* @param recvID Receiver's ID
* @param msgTip Customized tip message
*/
- (void)typingStatusUpdate:(NSString *)recvID
msgTip:(NSString *)msgTip
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Mark messages as read
*
* @param conversationID Conversation's ID
* @param clientMsgIDs ClientMsg's IDs
*/
- (void)markMessageAsReadByConID:(NSString *)conversationID
clientMsgIDs:(NSArray <NSString *> *)clientMsgIDs
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure __attribute__((deprecated("This method is deprecated. Use markConversationMessageAsRead instead.")));
/**
* Delete a message from local storage
*
* @param conversationID Conversation's ID
* @param clientMsgID ClientMsg's ID
*/
- (void)deleteMessageFromLocalStorage:(NSString *)conversationID
clientMsgID:(NSString *)clientMsgID
onSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure;
/**
* Delete a message from local and server
*
* @param conversationID Conversation's ID
* @param clientMsgID ClientMsg's ID
*/
- (void)deleteMessage:(NSString *)conversationID
clientMsgID:(NSString *)clientMsgID
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Delete all messages from local storage
*/
- (void)deleteAllMsgFromLocalWithOnSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Delete all messages from local and server
*/
- (void)deleteAllMsgFromLocalAndSvrWithOnSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Insert a one-on-one chat message into local storage
*
* @param recvID Receiver's user ID
* @param sendID Sender's user ID
*/
- (void)insertSingleMessageToLocalStorage:(OIMMessageInfo *)message
recvID:(NSString *)recvID
sendID:(NSString *)sendID
onSuccess:(nullable OIMMessageInfoCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Insert a group chat message into local storage
*
* @param groupID Group ID
* @param sendID Sender's user ID
*/
- (void)insertGroupMessageToLocalStorage:(OIMMessageInfo *)message
groupID:(NSString * _Nullable)groupID
sendID:(NSString * _Nullable)sendID
onSuccess:(nullable OIMMessageInfoCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Search for local messages
*
* @param param search param
*/
- (void)searchLocalMessages:(OIMSearchParam *)param
onSuccess:(nullable OIMMessageSearchCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Independently upload a file to the initialized SDK's Object Storage Service (OSS) (Not needed for sending multimedia messages, as it is automatically done by the SDK internally)
*
* @param fullPath Absolute file path.
* @param name file's name
* @param cause file's catogery
*/
- (void)uploadFile:(NSString *)fullPath
name:(NSString * _Nullable)name
cause:(NSString * _Nullable)cause
onProgress:(OIMUploadProgressCallback)onProgress
onCompletion:(OIMUploadCompletionCallback)onCompletion
onSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure;
/**
* Set global message notification options
*
* @param opt receiving method.
*/
- (void)setGlobalRecvMessageOpt:(OIMReceiveMessageOpt)opt
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure __attribute__((deprecated("Use OIMManager+User: setSelfInfo instead")));
/**
* Advanced Message Series Usage
*
* @param opts lastMinSeq is the value passed in the last pull callback, context, to be passed back in the second pull
*/
- (void)getAdvancedHistoryMessageList:(OIMGetAdvancedHistoryMessageListParam *)opts
onSuccess:(nullable OIMGetAdvancedHistoryMessageListCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Advanced Message Series Usage
*
* @param opts lastMinSeq is the value passed in the last pull callback, context, to be passed back in the second pull
*/
- (void)getAdvancedHistoryMessageListReverse:(OIMGetAdvancedHistoryMessageListParam *)opts
onSuccess:(nullable OIMGetAdvancedHistoryMessageListCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Find a list of messages
*
* @param param Find parameters.
*/
- (void)findMessageList:(NSArray<OIMFindMessageListParam *> *)param
onSuccess:(nullable OIMMessageSearchCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Set the application badge count and inform the server of the current count
*
* @param count Number of corners.
*/
- (void)setAppBadge:(NSInteger)count
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* For example, store the local state of a message
*
* @param conversationID Conversation's ID
* @param clientMsgID ClientMsg's ID
* @param localEx ex
*/
- (void)setMessageLocalEx:(NSString *)conversationID
clientMsgID:(NSString *)clientMsgID
localEx: (NSString *)localEx
onSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,506 @@
//
// OIMManager+Message.m
// OpenIMSDK
//
// Created by x on 2022/2/16.
//
#import "OIMManager+Message.h"
#import "SendMessageCallbackProxy.h"
@implementation OIMMessageInfo (extension)
- (BOOL)isSelf {
return [self.sendID isEqualToString:[OIMManager.manager getLoginUserID]];
}
+ (OIMMessageInfo *)convertToMessageInfo:(NSString *)json {
OIMMessageInfo *msg = [OIMMessageInfo mj_objectWithKeyValues:json];
msg.status = OIMMessageStatusUndefine;
return msg;
}
+ (OIMMessageInfo *)createTextMessage:(NSString *)text {
NSString *json = Open_im_sdkCreateTextMessage([OIMManager.manager operationId], text);
return [self convertToMessageInfo:json];
}
+ (OIMAtInfo *)createAtAllFlag:(NSString *)displayText {
OIMAtInfo *all = [OIMAtInfo new];
all.atUserID = [self getAtAllTag];
all.groupNickname = displayText ?: @"Mention All";
return all;
}
+ (NSString *)getAtAllTag {
NSString *tag = Open_im_sdkGetAtAllTag([OIMManager.manager operationId]);
tag = [tag stringByReplacingOccurrencesOfString:@"\"" withString:@""];
tag = [tag stringByReplacingOccurrencesOfString:@"\\" withString:@""];
return tag;
}
+ (OIMMessageInfo *)createTextAtMessage:(NSString *)text
atUsersID:(NSArray<NSString *> *)atUsersID
atUsersInfo:(NSArray<OIMAtInfo *> *)atUsersInfo
message:(OIMMessageInfo *)message {
NSArray *atUsers = [OIMAtInfo mj_keyValuesArrayWithObjectArray:atUsersInfo];
NSString *atUsersJson = [[NSString alloc]initWithData:[NSJSONSerialization dataWithJSONObject:atUsers options:0 error:nil] encoding:NSUTF8StringEncoding];
NSString *json = Open_im_sdkCreateTextAtMessage([OIMManager.manager operationId], text, atUsersID.mj_JSONString, atUsersJson, message ? message.mj_JSONString : @"");
return [self convertToMessageInfo:json];
}
+ (OIMMessageInfo *)createTextAtAllMessage:(NSString *)text
displayText:(NSString *)displayText
message:(OIMMessageInfo * _Nullable)message {
NSString *json = Open_im_sdkCreateTextAtMessage([OIMManager.manager operationId], text, @[Open_im_sdkGetAtAllTag([[NSUUID UUID]UUIDString])].mj_JSONString, @[@{Open_im_sdkGetAtAllTag([[NSUUID UUID]UUIDString]): displayText ?: @"@all members"}].mj_JSONString, message ? message.mj_JSONString : @"");
return [self convertToMessageInfo:json];
}
+ (OIMMessageInfo *)createImageMessage:(NSString *)imagePath {
NSString *json = Open_im_sdkCreateImageMessage([OIMManager.manager operationId], imagePath);
return [self convertToMessageInfo:json];
}
+ (OIMMessageInfo *)createImageMessageFromFullPath:(NSString *)imagePath {
NSString *json = Open_im_sdkCreateImageMessageFromFullPath([OIMManager.manager operationId], imagePath);
return [self convertToMessageInfo:json];
}
+ (OIMMessageInfo *)createImageMessageByURL:(NSString *)sourcePath
sourcePicture:(OIMPictureInfo *)source
bigPicture:(OIMPictureInfo *)big
snapshotPicture:(OIMPictureInfo *)snapshot {
NSString *json = Open_im_sdkCreateImageMessageByURL([OIMManager.manager operationId], sourcePath, source.mj_JSONString, big.mj_JSONString, snapshot.mj_JSONString);
return [self convertToMessageInfo:json];
}
+ (OIMMessageInfo *)createSoundMessage:(NSString *)soundPath
duration:(NSInteger)duration {
NSString *json = Open_im_sdkCreateSoundMessage([OIMManager.manager operationId], soundPath, duration);
return [self convertToMessageInfo:json];
}
+ (OIMMessageInfo *)createSoundMessageFromFullPath:(NSString *)soundPath
duration:(NSInteger)duration {
NSString *json = Open_im_sdkCreateSoundMessageFromFullPath([OIMManager.manager operationId], soundPath, duration);
return [self convertToMessageInfo:json];
}
+ (OIMMessageInfo *)createSoundMessageByURL:(NSString *)fileURL
duration:(NSInteger)duration
size:(NSInteger)size {
OIMSoundElem *elem = [OIMSoundElem new];
elem.sourceUrl = fileURL;
elem.duration = duration;
elem.dataSize = size;
NSString *json = Open_im_sdkCreateSoundMessageByURL([OIMManager.manager operationId], elem.mj_JSONString);
return [self convertToMessageInfo:json];
}
+ (OIMMessageInfo *)createVideoMessage:(NSString *)videoPath
videoType:(NSString *)videoType
duration:(NSInteger)duration
snapshotPath:(NSString *)snapshotPath {
NSString *json = Open_im_sdkCreateVideoMessage([OIMManager.manager operationId], videoPath, videoType, duration, snapshotPath);
return [self convertToMessageInfo:json];
}
+ (OIMMessageInfo *)createVideoMessageFromFullPath:(NSString *)videoPath
videoType:(NSString *)videoType
duration:(NSInteger)duration
snapshotPath:(NSString *)snapshotPath {
NSString *json = Open_im_sdkCreateVideoMessageFromFullPath([OIMManager.manager operationId], videoPath, videoType, duration, snapshotPath);
return [self convertToMessageInfo:json];
}
+ (OIMMessageInfo *)createVideoMessageByURL:(NSString *)fileURL
videoType:(NSString *)videoType
duration:(NSInteger)duration
size:(NSInteger)size
snapshot:(NSString *)snapshotURL {
OIMVideoElem *elem = [OIMVideoElem new];
elem.videoUrl = fileURL;
elem.videoType = videoType;
elem.duration = duration;
elem.videoSize = size;
elem.snapshotUrl = snapshotURL;
NSString *json = Open_im_sdkCreateVideoMessageByURL([OIMManager.manager operationId], elem.mj_JSONString);
return [self convertToMessageInfo:json];
}
+ (OIMMessageInfo *)createFileMessage:(NSString *)filePath
fileName:(NSString *)fileName {
NSString *json = Open_im_sdkCreateFileMessage([OIMManager.manager operationId], filePath, fileName);
return [self convertToMessageInfo:json];
}
+ (OIMMessageInfo *)createFileMessageFromFullPath:(NSString *)filePath
fileName:(NSString *)fileName {
NSString *json = Open_im_sdkCreateFileMessageFromFullPath([OIMManager.manager operationId], filePath, fileName);
return [self convertToMessageInfo:json];
}
+ (OIMMessageInfo *)createFileMessageByURL:(NSString *)fileURL
fileName:(NSString *)fileName
size:(NSInteger)size {
OIMFileElem *elem = [OIMFileElem new];
elem.sourceUrl = fileURL;
elem.fileName = fileName ?: fileURL.lastPathComponent;
elem.fileSize = size;
NSString *json = Open_im_sdkCreateFileMessageByURL([OIMManager.manager operationId], elem.mj_JSONString);
return [self convertToMessageInfo:json];
}
+ (OIMMessageInfo *)createMergeMessage:(NSArray<OIMMessageInfo *> *)messages
title:(NSString *)title
summaryList:(NSArray<NSString *> *)summarys {
NSArray *msgs = [OIMMessageInfo mj_keyValuesArrayWithObjectArray:messages];
NSString *json = Open_im_sdkCreateMergerMessage([OIMManager.manager operationId], [[NSString alloc]initWithData:[NSJSONSerialization dataWithJSONObject:msgs options:0 error:nil] encoding:NSUTF8StringEncoding], title, summarys.mj_JSONString);
return [self convertToMessageInfo:json];
}
+ (OIMMessageInfo *)createForwardMessage:(OIMMessageInfo *)message {
NSString *json = Open_im_sdkCreateForwardMessage([OIMManager.manager operationId], message.mj_JSONString);
return [OIMMessageInfo mj_objectWithKeyValues:json];
}
+ (OIMMessageInfo *)createLocationMessage:(NSString *)description
latitude:(double)latitude
longitude:(double)longitude {
NSString *json = Open_im_sdkCreateLocationMessage([OIMManager.manager operationId], description, longitude, latitude);
return [self convertToMessageInfo:json];
}
+ (OIMMessageInfo *)createQuoteMessage:(NSString *)text
message:(OIMMessageInfo *)message {
NSString *json = Open_im_sdkCreateQuoteMessage([OIMManager.manager operationId], text, message.mj_JSONString);
return [self convertToMessageInfo:json];
}
+ (OIMMessageInfo *)createCardMessage:(OIMCardElem *)card {
NSString *json = Open_im_sdkCreateCardMessage([OIMManager.manager operationId], card.mj_JSONString);
return [self convertToMessageInfo:json];
}
+ (OIMMessageInfo *)createCustomMessage:(NSString *)data
extension:(NSString *)extension
description:(NSString *)description {
NSString *json = Open_im_sdkCreateCustomMessage([OIMManager.manager operationId], data, extension, description);
return [self convertToMessageInfo:json];
}
+ (OIMMessageInfo *)createFaceMessageWithIndex:(NSInteger)index
data:(NSString *)dataStr {
NSString *json = Open_im_sdkCreateFaceMessage([OIMManager.manager operationId], index, dataStr);
return [self convertToMessageInfo:json];
}
+ (OIMMessageInfo *)createAdvancedTextMessage:(NSString *)text
messageEntityList:(NSArray<OIMMessageEntity *> *)messageEntityList {
NSArray *msgs = [OIMMessageEntity mj_keyValuesArrayWithObjectArray:messageEntityList];
NSString *json = Open_im_sdkCreateAdvancedTextMessage([OIMManager.manager operationId], text, [[NSString alloc]initWithData:[NSJSONSerialization dataWithJSONObject:msgs options:0 error:nil] encoding:NSUTF8StringEncoding]);
return [self convertToMessageInfo:json];
}
+ (OIMMessageInfo *)createAdvancedQuoteMessage:(NSString *)text
message:(OIMMessageInfo *)message
messageEntityList:(NSArray<OIMMessageEntity *> *)messageEntityList {
NSArray *msgs = [OIMMessageEntity mj_keyValuesArrayWithObjectArray:messageEntityList];
NSString *json = Open_im_sdkCreateAdvancedQuoteMessage([OIMManager.manager operationId], text, message.mj_JSONString, [[NSString alloc]initWithData:[NSJSONSerialization dataWithJSONObject:msgs options:0 error:nil] encoding:NSUTF8StringEncoding]);
return [self convertToMessageInfo:json];
}
@end
@implementation OIMManager (Message)
- (void)sendMessage:(OIMMessageInfo *)message
recvID:(NSString *)recvID
groupID:(NSString *)groupID
offlinePushInfo:(OIMOfflinePushInfo *)offlinePushInfo
onSuccess:(OIMMessageInfoCallback)onSuccess
onProgress:(OIMNumberCallback)onProgress
onFailure:(OIMFailureCallback)onFailure {
[self sendMessage:message
recvID:recvID
groupID:groupID
isOnlineOnly:false
offlinePushInfo:offlinePushInfo
onSuccess:onSuccess
onProgress:onProgress
onFailure:onFailure];
}
- (void)sendMessage:(OIMMessageInfo *)message
recvID:(NSString * _Nullable)recvID
groupID:(NSString * _Nullable)groupID
isOnlineOnly:(BOOL)isOnlineOnly
offlinePushInfo:(OIMOfflinePushInfo * _Nullable)offlinePushInfo
onSuccess:(nullable OIMMessageInfoCallback)onSuccess
onProgress:(nullable OIMNumberCallback)onProgress
onFailure:(nullable OIMFailureCallback)onFailure {
assert(recvID.length != 0 || groupID.length != 0);
SendMessageCallbackProxy *callback = [[SendMessageCallbackProxy alloc]initWithOnSuccess:^(NSString * _Nullable data) {
if (onSuccess) {
onSuccess([OIMMessageInfo mj_objectWithKeyValues:data]);
}
} onProgress:onProgress onFailure:onFailure];
Open_im_sdkSendMessage(callback, [self operationId], message.mj_JSONString, recvID ?: @"", groupID ?: @"", offlinePushInfo ? offlinePushInfo.mj_JSONString : @"{}", isOnlineOnly);
}
- (void)sendMessageNotOss:(OIMMessageInfo *)message
recvID:(NSString *)recvID
groupID:(NSString *)groupID
offlinePushInfo:(OIMOfflinePushInfo *)offlinePushInfo
onSuccess:(OIMMessageInfoCallback)onSuccess
onProgress:(OIMNumberCallback)onProgress
onFailure:(OIMFailureCallback)onFailure {
assert(recvID.length != 0 || groupID.length != 0);
[self sendMessageNotOss:message
recvID:recvID
groupID:groupID
isOnlineOnly:false
offlinePushInfo:offlinePushInfo
onSuccess:onSuccess
onProgress:onProgress
onFailure:onFailure];
}
- (void)sendMessageNotOss:(OIMMessageInfo *)message
recvID:(NSString *)recvID
groupID:(NSString *)groupID
isOnlineOnly:(BOOL)isOnlineOnly
offlinePushInfo:(OIMOfflinePushInfo *)offlinePushInfo
onSuccess:(OIMMessageInfoCallback)onSuccess
onProgress:(OIMNumberCallback)onProgress
onFailure:(OIMFailureCallback)onFailure {
assert(recvID.length != 0 || groupID.length != 0);
SendMessageCallbackProxy *callback = [[SendMessageCallbackProxy alloc]initWithOnSuccess:^(NSString * _Nullable data) {
if (onSuccess) {
onSuccess([OIMMessageInfo mj_objectWithKeyValues:data]);
}
} onProgress:onProgress onFailure:onFailure];
Open_im_sdkSendMessageNotOss(callback, [self operationId], message.mj_JSONString, recvID, groupID, offlinePushInfo.mj_JSONString, isOnlineOnly);
}
- (void)revokeMessage:(NSString *)conversationID
clientMsgID:(NSString *)clientMsgID
onSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:onSuccess onFailure:onFailure];
Open_im_sdkRevokeMessage(callback, [self operationId], conversationID, clientMsgID);
}
- (void)typingStatusUpdate:(NSString *)recvID
msgTip:(NSString *)msgTip
onSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:onSuccess onFailure:onFailure];
Open_im_sdkTypingStatusUpdate(callback, [self operationId], recvID, msgTip);
}
- (void)markMessageAsReadByConID:(NSString *)conversationID
clientMsgIDs:(NSArray <NSString *> *)clientMsgIDs
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:onSuccess onFailure:onFailure];
Open_im_sdkMarkMessagesAsReadByMsgID(callback, [self operationId], conversationID, clientMsgIDs.mj_JSONString);
}
- (void)deleteMessage:(NSString *)conversationID
clientMsgID:(NSString *)clientMsgID
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:onSuccess onFailure:onFailure];
Open_im_sdkDeleteMessage(callback, [self operationId], conversationID, clientMsgID);
}
- (void)deleteMessageFromLocalStorage:(NSString *)conversationID
clientMsgID:(NSString *)clientMsgID
onSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:onSuccess onFailure:onFailure];
Open_im_sdkDeleteMessageFromLocalStorage(callback, [self operationId], conversationID, clientMsgID);
}
- (void)deleteAllMsgFromLocalWithOnSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:onSuccess onFailure:onFailure];
Open_im_sdkDeleteAllMsgFromLocal(callback, [self operationId]);
}
- (void)deleteAllMsgFromLocalAndSvrWithOnSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:onSuccess onFailure:onFailure];
Open_im_sdkDeleteAllMsgFromLocalAndSvr(callback, [self operationId]);
}
- (void)insertSingleMessageToLocalStorage:(OIMMessageInfo *)message
recvID:(NSString *)recvID
sendID:(NSString *)sendID
onSuccess:(OIMMessageInfoCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:^(NSString * _Nullable data) {
if (onSuccess) {
onSuccess([OIMMessageInfo mj_objectWithKeyValues:data]);
}
} onFailure:onFailure];
Open_im_sdkInsertSingleMessageToLocalStorage(callback, [self operationId], message.mj_JSONString, recvID, sendID);
}
- (void)insertGroupMessageToLocalStorage:(OIMMessageInfo *)message
groupID:(NSString *)groupID
sendID:(NSString *)sendID
onSuccess:(OIMMessageInfoCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:^(NSString * _Nullable data) {
if (onSuccess) {
onSuccess([OIMMessageInfo mj_objectWithKeyValues:data]);
}
} onFailure:onFailure];
Open_im_sdkInsertGroupMessageToLocalStorage(callback, [self operationId], message.mj_JSONString, groupID, sendID);
}
- (void)searchLocalMessages:(OIMSearchParam *)param
onSuccess:(OIMMessageSearchCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:^(NSString * _Nullable data) {
if (onSuccess) {
onSuccess([OIMSearchResultInfo mj_objectWithKeyValues:data]);
}
} onFailure:onFailure];
Open_im_sdkSearchLocalMessages(callback, [self operationId], param.mj_JSONString);
}
- (void)uploadFile:(NSString *)fullPath
name:(NSString * _Nullable)name
cause:(NSString * _Nullable)cause
onProgress:(OIMUploadProgressCallback)onProgress
onCompletion:(OIMUploadCompletionCallback)onCompletion
onSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:onSuccess onFailure:onFailure];
UploadFileCallbackProxy *upload = [[UploadFileCallbackProxy alloc]initWithOnProgress:onProgress onCompletion:onCompletion];
NSDictionary *param = @{@"putID": fullPath.lastPathComponent,
@"name": name ?: fullPath.lastPathComponent,
@"filepath": fullPath,
@"cause": cause ?: @""};
Open_im_sdkUploadFile(callback, [self operationId], param.mj_JSONString, upload);
}
- (void)setGlobalRecvMessageOpt:(OIMReceiveMessageOpt)opt
onSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
}
- (void)getAdvancedHistoryMessageList:(OIMGetAdvancedHistoryMessageListParam *)opts
onSuccess:(OIMGetAdvancedHistoryMessageListCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:^(NSString * _Nullable data) {
if (onSuccess) {
onSuccess([OIMGetAdvancedHistoryMessageListInfo mj_objectWithKeyValues:data]);
}
} onFailure:onFailure];
Open_im_sdkGetAdvancedHistoryMessageList(callback, [self operationId], opts.mj_JSONString);
}
- (void)getAdvancedHistoryMessageListReverse:(OIMGetAdvancedHistoryMessageListParam *)opts
onSuccess:(nullable OIMGetAdvancedHistoryMessageListCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:^(NSString * _Nullable data) {
if (onSuccess) {
onSuccess([OIMGetAdvancedHistoryMessageListInfo mj_objectWithKeyValues:data]);
}
} onFailure:onFailure];
Open_im_sdkGetAdvancedHistoryMessageListReverse(callback, [self operationId], opts.mj_JSONString);
}
- (void)findMessageList:(NSArray<OIMFindMessageListParam *> *)param
onSuccess:(OIMMessageSearchCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:^(NSString * _Nullable data) {
if (onSuccess) {
onSuccess([OIMSearchResultInfo mj_objectWithKeyValues:data]);
}
} onFailure:onFailure];
NSArray *params = [OIMFindMessageListParam mj_keyValuesArrayWithObjectArray:param];
Open_im_sdkFindMessageList(callback, [self operationId], params.mj_JSONString);
}
- (void)setAppBadge:(NSInteger)count
onSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:onSuccess onFailure:onFailure];
Open_im_sdkSetAppBadge(callback, [self operationId], (int32_t)count);
}
- (void)setMessageLocalEx:(NSString *)conversationID
clientMsgID:(NSString *)clientMsgID
localEx: (NSString *)localEx
onSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:onSuccess onFailure:onFailure];
Open_im_sdkSetMessageLocalEx(callback, [self operationId], conversationID, clientMsgID, localEx);
}
@end

View File

@ -0,0 +1,89 @@
//
// OIMManager+User.h
// OpenIMSDK
//
// Created by x on 2022/2/16.
//
#import "OIMManager.h"
NS_ASSUME_NONNULL_BEGIN
@interface OIMManager (User)
/**
* Batch query user information by uid
*
* @param uids List of user IDs
*/
- (void)getUsersInfo:(NSArray <NSString *> *)uids
onSuccess:(nullable OIMPublicUsersInfoCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Modify the information of the currently logged-in user
*
*/
- (void)setSelfInfo:(OIMUserInfo *)userInfo
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Information of the currently logged-in user
*
*/
- (void)getSelfInfoWithOnSuccess:(nullable OIMUserInfoCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Update FCM token
* @param fcmToken FCM Token
* @param expireTime expire time, unit: s
*/
- (void)updateFcmToken:(NSString *)fcmToken
expireTime:(NSInteger)expireTime
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Subscribe to the online status of users
*/
- (void)subscribeUsersStatus:(NSArray<NSString *> *)userIDs
onSuccess:(nullable OIMUserStatusInfosCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Unsubscribe from the online status of users
*/
- (void)unsubscribeUsersStatus:(NSArray<NSString *> *)userIDs
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Get the online status of all subscribed users
*/
- (void)getSubscribeUsersStatusWithOnSuccess:(nullable OIMUserStatusInfosCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
/**
* Get user status for regular users
*/
- (void)getUserStatus:(NSArray<NSString *> *)userIDs
onSuccess:(nullable OIMUserStatusInfosCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
- (void)getUsersInfoWithCache:(NSArray<NSString *> *)userIDs
groupID:(NSString * _Nullable)groupID
onSuccess:(nullable OIMPublicUsersInfoCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure __attribute__((deprecated("Use getUsersInfo instead")));
/// Global Do Not Disturb
/// [status] 0: Normal; 1: Do not accept messages; 2: Accept online messages but not offline messages;
- (void)setGlobalRecvMessageOpt:(NSInteger )status
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,117 @@
//
// OIMManager+User.m
// OpenIMSDK
//
// Created by x on 2022/2/16.
//
#import "OIMManager+User.h"
#import "CallbackProxy.h"
@implementation OIMManager (User)
- (void)getUsersInfo:(NSArray <NSString *> *)uids
onSuccess:(OIMPublicUsersInfoCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:^(NSString * _Nullable data) {
if (onSuccess) {
onSuccess([OIMPublicUserInfo mj_objectArrayWithKeyValuesArray:data]);
}
} onFailure:onFailure];
Open_im_sdkGetUsersInfo(callback, [self operationId], uids.mj_JSONString);
}
- (void)setSelfInfo:(OIMUserInfo *)userInfo
onSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:onSuccess onFailure:onFailure];
Open_im_sdkSetSelfInfo(callback, [self operationId], userInfo.mj_JSONString);
}
- (void)getSelfInfoWithOnSuccess:(OIMUserInfoCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:^(NSString * _Nullable data) {
if (onSuccess) {
onSuccess([OIMUserInfo mj_objectWithKeyValues:data]);
}
} onFailure:onFailure];
Open_im_sdkGetSelfUserInfo(callback, [self operationId]);
}
- (void)updateFcmToken:(NSString *)fmcToken
expireTime:(NSInteger)expireTime
onSuccess:(OIMSuccessCallback)onSuccess
onFailure:(OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:onSuccess onFailure:onFailure];
Open_im_sdkUpdateFcmToken(callback, [self operationId], fmcToken, expireTime);
}
- (void)subscribeUsersStatus:(NSArray<NSString *> *)userIDs
onSuccess:(nullable OIMUserStatusInfosCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:^(NSString * _Nullable data) {
if (onSuccess) {
onSuccess([OIMUserStatusInfo mj_objectArrayWithKeyValuesArray:data]);
}
} onFailure:onFailure];
Open_im_sdkSubscribeUsersStatus(callback, [self operationId], userIDs.mj_JSONString);
}
- (void)unsubscribeUsersStatus:(NSArray<NSString *> *)userIDs
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:onSuccess onFailure:onFailure];
Open_im_sdkUnsubscribeUsersStatus(callback, [self operationId], userIDs.mj_JSONString);
}
- (void)getSubscribeUsersStatusWithOnSuccess:(nullable OIMUserStatusInfosCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:^(NSString * _Nullable data) {
if (onSuccess) {
onSuccess([OIMUserStatusInfo mj_objectArrayWithKeyValuesArray:data]);
}
} onFailure:onFailure];
Open_im_sdkGetSubscribeUsersStatus(callback, [self operationId]);
}
- (void)getUserStatus:(NSArray<NSString *> *)userIDs
onSuccess:(nullable OIMUserStatusInfosCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:^(NSString * _Nullable data) {
if (onSuccess) {
onSuccess([OIMUserStatusInfo mj_objectArrayWithKeyValuesArray:data]);
}
} onFailure:onFailure];
Open_im_sdkGetUserStatus(callback, [self operationId], userIDs.mj_JSONString);
}
- (void)getUsersInfoWithCache:(NSArray<NSString *> *)userIDs
groupID:(NSString *)groupID
onSuccess:(nullable OIMPublicUsersInfoCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:^(NSString * _Nullable data) {
if (onSuccess) {
onSuccess([OIMPublicUserInfo mj_objectArrayWithKeyValuesArray:data]);
}
} onFailure:onFailure];
Open_im_sdkGetUsersInfo(callback, [self operationId], userIDs.mj_JSONString);
}
- (void)setGlobalRecvMessageOpt:(NSInteger )status
onSuccess:(nullable OIMSuccessCallback)onSuccess
onFailure:(nullable OIMFailureCallback)onFailure {
OIMUserInfo *info = [OIMUserInfo new];
info.globalRecvMsgOpt = status;
[self setSelfInfo:info onSuccess:onSuccess onFailure:onFailure];
}
@end

View File

@ -0,0 +1,37 @@
//
// OIMManager.h
// OpenIMSDK
//
// Created by x on 2022/2/15.
//
#import <Foundation/Foundation.h>
#import "OIMCallbacker.h"
NS_ASSUME_NONNULL_BEGIN
@interface OIMManager : NSObject
+ (instancetype)manager;
/**
* All listeners setup here (User, Friend, Group, Conversation, AdvancedMsg, etc.)
*/
@property (nonatomic, strong, class, readonly) OIMManager *manager;
@property (nonatomic, strong, class, readonly) OIMCallbacker *callbacker;
@property (nonatomic, copy, nullable) NSString *token;
@property (nonatomic, copy, nullable) NSString *objectStorage;
/**
* SDK version number
*/
+ (NSString *)sdkSdkVersion;
/**
* Get the login user's UID
*/
- (NSString *)getLoginUserID;
- (NSString *)operationId;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,120 @@
//
// OIMManager.m
// OpenIMSDK
//
// Created by x on 2022/2/15.
//
#import "OIMManager.h"
#import "OIMReachability.h"
#import "CallbackProxy.h"
@interface OIMManager ()
{
OIMCallbacker *_callbacker;
OIMReachability *internetReachability;
}
@end
@implementation OIMManager
@dynamic callbacker;
+ (instancetype)manager {
static OIMManager *instance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[OIMManager alloc]init];
});
return instance;
}
- (instancetype)init {
if (self = [super init]) {
// This method will be called when the app enters the foreground from the background.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(applicationWillEnterForeground:)
name:UIApplicationWillEnterForegroundNotification
object:nil];
//Add an observer to detect when the app enters the background
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(applicationDidEnterBackground:)
name:UIApplicationDidEnterBackgroundNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(reachabilityChanged:)
name:kReachabilityChangedNotification
object:nil];
internetReachability = [OIMReachability reachabilityForInternetConnection];
[internetReachability startNotifier];
}
return self;
}
+ (OIMCallbacker *)callbacker {
return [OIMManager manager].callbacker;
}
- (OIMCallbacker *)callbacker {
if (_callbacker == nil) {
_callbacker = [OIMCallbacker callbacker];
}
return _callbacker;
}
+ (NSString *)sdkSdkVersion
{
return Open_im_sdkGetSdkVersion();
}
- (NSString *)getLoginUserID {
return Open_im_sdkGetLoginUserID();
}
- (NSString *)operationId {
NSDate *date = [NSDate dateWithTimeIntervalSinceNow:0];
NSTimeInterval time = [date timeIntervalSince1970] * 1000;
return [NSString stringWithFormat:@"%ld", (NSInteger)time];
}
- (void)applicationDidEnterBackground:(NSNotification *)note {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:^(NSString * _Nullable data) {
} onFailure:^(NSInteger code, NSString * _Nullable msg) {
}];
Open_im_sdkSetAppBackgroundStatus(callback, [self operationId], YES);
}
- (void)applicationWillEnterForeground:(NSNotification *)note {
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:^(NSString * _Nullable data) {
} onFailure:^(NSInteger code, NSString * _Nullable msg) {
}];
Open_im_sdkSetAppBackgroundStatus(callback, [self operationId], NO);
}
- (void)reachabilityChanged:(NSNotification *)note {
OIMReachability *reachability = [note object];
NSParameterAssert([reachability isKindOfClass:[OIMReachability class]]);
CallbackProxy *callback = [[CallbackProxy alloc]initWithOnSuccess:^(NSString * _Nullable data) {
} onFailure:^(NSInteger code, NSString * _Nullable msg) {
}];
Open_im_sdkNetworkStatusChanged(callback, [self operationId]);
}
@end

View File

@ -0,0 +1,61 @@
//
// OIMAtElem.h
// OpenIMSDK
//
// Created by x on 2022/2/11.
//
#import <Foundation/Foundation.h>
#import "OIMQuoteElem.h"
NS_ASSUME_NONNULL_BEGIN
@interface OIMAtInfo : NSObject
/**
* ID of the member being mentioned
*/
@property (nonatomic, nullable, copy) NSString *atUserID;
/**
* Nickname or group nickname of the mentioned member
*/
@property (nonatomic, nullable, copy) NSString *groupNickname;
@end
@interface OIMAtTextElem : NSObject
/**
* Mentioned message content
*/
@property (nonatomic, nullable, copy) NSString *text;
/**
* Set of user IDs being mentioned
*/
@property (nonatomic, nullable, copy) NSArray<NSString *> *atUserList;
/**
* Set of mentioned users
*/
@property (nonatomic, nullable, copy) NSArray<OIMAtInfo *> *atUsersInfo;
/**
* Quoted message with @ mention
*/
@property (nonatomic, nullable, strong) OIMMessageInfo *quoteMessage;
/**
* Whether the sender is mentioned (@)
*/
@property (nonatomic, assign, readonly) BOOL isAtSelf;
/**
* Whether @ all members
*/
@property (nonatomic, assign, readonly) BOOL isAtAll;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,30 @@
//
// OIMAtElem.h
// OpenIMSDK
//
// Created by x on 2022/2/11.
//
#import "OIMAtElem.h"
#import <MJExtension/MJExtension.h>
@import OpenIMCore;
@implementation OIMAtInfo
@end
@implementation OIMAtTextElem
+ (NSDictionary *)mj_objectClassInArray
{
return @{@"atUsersInfo" : [OIMAtInfo class]};
}
- (BOOL)isAtAll {
return self.atUserList.count > 0 &&
[self.atUserList.firstObject isKindOfClass:[NSString class]] &&
[self.atUserList.firstObject isEqualToString:Open_im_sdkGetAtAllTag([[NSUUID UUID]UUIDString])];
}
@end

View File

@ -0,0 +1,59 @@
//
// OIMAttachedInfoElem.h
// OpenIMSDK
//
// Created by x on 2022/3/18.
//
#import <Foundation/Foundation.h>
#import "OIMMessageElem.h"
NS_ASSUME_NONNULL_BEGIN
/// Users who have read the message
///
@interface OIMGroupHasReadInfo : NSObject
@property (nonatomic, nullable, copy) NSArray <NSString *> *hasReadUserIDList;
@property (nonatomic, assign) NSInteger hasReadCount;
/**
* Number of group members at the time of sending this message
*/
@property (nonatomic, assign) NSInteger groupMemberCount;
@end
@interface OIMUploadProgress : NSObject
@property (nonatomic, assign) NSInteger total;
@property (nonatomic, assign) NSInteger save;
@property (nonatomic, assign) NSInteger current;
@end
@interface OIMAttachedInfoElem : NSObject
@property (nonatomic, nullable, strong) OIMGroupHasReadInfo *groupHasReadInfo;
@property (nonatomic, assign) BOOL isPrivateChat;
@property (nonatomic, assign) NSTimeInterval burnDuration;
@property (nonatomic, assign) NSTimeInterval hasReadTime;
@property (nonatomic, assign) BOOL notSenderNotificationPush;
@property (nonatomic, copy) NSArray <OIMMessageEntity *> *messageEntityList;
@property (nonatomic, assign) BOOL isEncryption;
@property (nonatomic, assign) BOOL inEncryptStatus;
@property (nonatomic, strong) OIMUploadProgress *uploadProgress;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,26 @@
//
// OIMAttachedInfoElem.m
// OpenIMSDK
//
// Created by x on 2022/3/18.
//
#import "OIMAttachedInfoElem.h"
#import <MJExtension/MJExtension.h>
@implementation OIMGroupHasReadInfo
@end
@implementation OIMUploadProgress
@end
@implementation OIMAttachedInfoElem
+ (NSDictionary *)mj_objectClassInArray
{
return @{@"messageEntityList" : [OIMMessageEntity class]};
}
@end

View File

@ -0,0 +1,120 @@
//
// OIMConversationInfo.h
// OpenIMSDK
//
// Created by x on 2022/2/11.
//
#import <Foundation/Foundation.h>
#import "OIMMessageInfo.h"
NS_ASSUME_NONNULL_BEGIN
/// Conversation Information
///
@interface OIMConversationBaseInfo : NSObject
@property (nonatomic, nullable, copy) NSString *conversationID;
@end
/// Conversation Information
///
@interface OIMConversationInfo : OIMConversationBaseInfo
@property (nonatomic, assign) OIMConversationType conversationType;
@property (nonatomic, nullable, copy) NSString *userID;
@property (nonatomic, nullable, copy) NSString *groupID;
@property (nonatomic, nullable, copy) NSString *showName;
@property (nonatomic, nullable, copy) NSString *faceURL;
@property (nonatomic, assign) OIMReceiveMessageOpt recvMsgOpt;
@property (nonatomic, assign) NSInteger unreadCount;
@property (nonatomic, assign) OIMGroupAtType groupAtType;
@property (nonatomic, assign) NSInteger latestMsgSendTime;
@property (nonatomic, nullable, copy) NSString *draftText;
@property (nonatomic, assign) NSInteger draftTextTime;
@property (nonatomic, assign) BOOL isPinned;
/**
* Whether private chat (burn after reading) is enabled
*/
@property (nonatomic, assign) BOOL isPrivateChat;
/**
* Private chat duration
*/
@property (nonatomic, assign) NSTimeInterval burnDuration;
/**
* Whether still in the group, return true if left the group
*/
@property (nonatomic, assign) BOOL isNotInGroup;
@property (nonatomic, nullable, copy) NSString *attachedInfo;
@property (nonatomic, nullable, strong) OIMMessageInfo *latestMsg;
@property (nonatomic, nullable, copy) NSString *ex;
@end
/// Do Not Disturb Conversation Information
///
@interface OIMConversationNotDisturbInfo : OIMConversationBaseInfo
/**
* Do Not Disturb Status
*/
@property (nonatomic, assign) OIMReceiveMessageOpt result;
@end
/// input status Information
///
@interface OIMInputStatusChangedData : NSObject
@property (nonatomic, copy) NSString *conversationID;
@property (nonatomic, copy) NSString *userID;
// OIMPlatform
@property (nonatomic, copy) NSArray<NSNumber *> *platformIDs;
@end
@interface OIMConversationReq : NSObject
@property (nonatomic, nullable, copy) NSString *userID;
@property (nonatomic, nullable, copy) NSString *groupID;
@property (nonatomic, assign) OIMReceiveMessageOpt recvMsgOpt;
@property (nonatomic, assign) BOOL isPinned;
@property (nonatomic, assign) OIMGroupAtType groupAtType;
/**
* Whether private chat (burn after reading) is enabled
*/
@property (nonatomic, assign) BOOL isPrivateChat;
/**
* Private chat duration
*/
@property (nonatomic, assign) NSTimeInterval burnDuration;
@property (nonatomic, nullable, copy) NSString *ex;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,28 @@
//
// OIMConversationInfo.h
// OpenIMSDK
//
// Created by x on 2022/2/11.
//
#import "OIMConversationInfo.h"
@implementation OIMConversationBaseInfo
@end
@implementation OIMConversationInfo
@end
@implementation OIMConversationNotDisturbInfo
@end
@implementation OIMInputStatusChangedData
@end
@implementation OIMConversationReq
@end

View File

@ -0,0 +1,22 @@
//
// OIMCustomElem.h
// OpenIMSDK
//
// Created by x on 2022/2/11.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface OIMCustomElem : NSObject
@property (nonatomic, nullable, copy) NSString *data;
@property (nonatomic, nullable, copy) NSString *extension;
@property (nonatomic, nullable, copy) NSString *description_;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,17 @@
//
// OIMCustomElem.h
// OpenIMSDK
//
// Created by x on 2022/2/11.
//
#import "OIMCustomElem.h"
#import <MJExtension/MJExtension.h>
@implementation OIMCustomElem
+ (NSDictionary *)mj_replacedKeyFromPropertyName {
return @{@"description_" : @"description"};
}
@end

View File

@ -0,0 +1,19 @@
//
// OIMFaceElem.h
// OpenIMSDK
//
// Created by x on 2022/3/9.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface OIMFaceElem : NSObject
@property (nonatomic, assign) NSInteger index;
@property (nonatomic, nullable, copy) NSString *data;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,12 @@
//
// OIMFaceElem.m
// OpenIMSDK
//
// Created by x on 2022/3/9.
//
#import "OIMFaceElem.h"
@implementation OIMFaceElem
@end

View File

@ -0,0 +1,41 @@
//
// OIMFileElem.h
// OpenIMSDK
//
// Created by x on 2022/2/11.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface OIMFileElem : NSObject
/**
* Local resource address of the file
*/
@property (nonatomic, nullable, copy) NSString *filePath;
/**
* UUID
*/
@property (nonatomic, nullable, copy) NSString *uuID;
/**
* OSS address
*/
@property (nonatomic, nullable, copy) NSString *sourceUrl;
/**
* File name
*/
@property (nonatomic, nullable, copy) NSString *fileName;
/**
* File size
*/
@property (nonatomic, assign) NSInteger fileSize;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,12 @@
//
// OIMFileElem.m
// Open-IM-SDK-iOS
//
// Created by xpg on 2021/11/5.
//
#import "OIMFileElem.h"
@implementation OIMFileElem
@end

View File

@ -0,0 +1,46 @@
//
// OIMFriendApplication.h
// OpenIMSDK
//
// Created by x on 2022/2/11.
//
#import <Foundation/Foundation.h>
#import "OIMMessageInfo.h"
NS_ASSUME_NONNULL_BEGIN
/// Friend application information, indicating who is applying to add whom as a friend and the result of handling the application.
///
@interface OIMFriendApplication : NSObject
@property (nonatomic, nullable, copy) NSString *fromUserID;
@property (nonatomic, nullable, copy) NSString *fromNickname;
@property (nonatomic, nullable, copy) NSString *fromFaceURL;
@property (nonatomic, nullable, copy) NSString *toUserID;
@property (nonatomic, nullable, copy) NSString *toNickname;
@property (nonatomic, nullable, copy) NSString *toFaceURL;
@property (nonatomic, assign) OIMApplicationStatus handleResult;
@property (nonatomic, nullable, copy) NSString *reqMsg;
@property (nonatomic, assign) NSInteger createTime;
@property (nonatomic, nullable, copy) NSString *handlerUserID;
@property (nonatomic, nullable, copy) NSString *handleMsg;
@property (nonatomic, assign) NSInteger handleTime;
@property (nonatomic, nullable, copy) NSString *ex;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,12 @@
//
// OIMFriendApplication.m
// OpenIMSDK
//
// Created by x on 2022/2/11.
//
#import "OIMFriendApplication.h"
@implementation OIMFriendApplication
@end

View File

@ -0,0 +1,66 @@
//
// OIMFullUserInfo.h
// OpenIMSDK
//
// Created by x on 2022/2/11.
//
#import <Foundation/Foundation.h>
#import "OIMDefine.h"
NS_ASSUME_NONNULL_BEGIN
/// Public user information, mainly basic information, excluding other privacy fields such as phone number.
///
@interface OIMPublicUserInfo : NSObject
@property (nonatomic, nullable, copy) NSString *userID;
@property (nonatomic, nullable, copy) NSString *nickname;
@property (nonatomic, nullable, copy) NSString *faceURL;
@property (nonatomic, nullable, copy) NSString *ex;
@end
/// Blacklist information, basic information of users in the blacklist. Note that the blacklist is a mutual relationship.
///
@interface OIMBlackInfo : OIMPublicUserInfo
@property (nonatomic, assign) NSInteger createTime;
@property (nonatomic, assign) NSInteger addSource;
@property (nonatomic, nullable, copy) NSString *operatorUserID;
@property (nonatomic, nullable, copy) NSString *attachedInfo;
@end
/// Friend information, basic information of users who are friends. Note that the blacklist is a mutual relationship.
///
@interface OIMFriendInfo : OIMPublicUserInfo
@property (nonatomic, nullable, copy) NSString *ownerUserID;
@property (nonatomic, nullable, copy) NSString *remark;
@property (nonatomic, assign) NSInteger createTime;
@property (nonatomic, assign) NSInteger addSource;
@property (nonatomic, nullable, copy) NSString *operatorUserID;
@property (nonatomic, nullable, copy) NSString *attachedInfo;
@end
@interface OIMSearchFriendsInfo : OIMFriendInfo
@property (nonatomic, assign) OIMRelationship relationship;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,24 @@
//
// OIMFullUserInfo.m
// OpenIMSDK
//
// Created by x on 2022/2/11.
//
#import "OIMFullUserInfo.h"
@implementation OIMPublicUserInfo
@end
@implementation OIMBlackInfo
@end
@implementation OIMFriendInfo
@end
@implementation OIMSearchFriendsInfo
@end

View File

@ -0,0 +1,44 @@
//
// OIMGroupApplicationInfo.h
// OpenIMSDK
//
// Created by x on 2022/2/11.
//
#import <Foundation/Foundation.h>
#import "OIMDefine.h"
NS_ASSUME_NONNULL_BEGIN
/// Group joining application information
///
@interface OIMGroupApplicationInfo : NSObject
@property (nonatomic, nullable, copy) NSString *groupID;
@property (nonatomic, nullable, copy) NSString *groupName;
@property (nonatomic, nullable, copy) NSString *notification;
@property (nonatomic, nullable, copy) NSString *introduction;
@property (nonatomic, nullable, copy) NSString *groupFaceURL;
@property (nonatomic, assign) NSInteger createTime;
@property (nonatomic, assign) NSInteger status;
@property (nonatomic, nullable, copy) NSString *creatorUserID;
@property (nonatomic, assign) NSInteger groupType;
@property (nonatomic, nullable, copy) NSString *ownerUserID;
@property (nonatomic, assign) NSInteger memberCount;
@property (nonatomic, nullable, copy) NSString *userID;
@property (nonatomic, nullable, copy) NSString *nickname;
@property (nonatomic, nullable, copy) NSString *userFaceURL;
@property (nonatomic, assign) OIMApplicationStatus handleResult;
@property (nonatomic, nullable, copy) NSString *reqMsg;
@property (nonatomic, nullable, copy) NSString *handledMsg;
@property (nonatomic, assign) NSInteger reqTime;
@property (nonatomic, nullable, copy) NSString *handleUserID;
@property (nonatomic, assign) NSInteger handledTime;
@property (nonatomic, nullable, copy) NSString *ex;
@property (nonatomic, nullable, copy) NSString *inviterUserID;
@property (nonatomic, assign) OIMJoinType joinSource;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,12 @@
//
// OIMGroupApplicationInfo.h
// OpenIMSDK
//
// Created by x on 2022/2/11.
//
#import "OIMGroupApplicationInfo.h"
@implementation OIMGroupApplicationInfo
@end

View File

@ -0,0 +1,51 @@
//
// OIMGroupInfo.h
// OpenIMSDK
//
// Created by x on 2022/2/11.
//
#import <Foundation/Foundation.h>
#import "OIMDefine.h"
NS_ASSUME_NONNULL_BEGIN
@interface OIMGroupBaseInfo : NSObject
@property (nonatomic, assign) OIMGroupType groupType;
@property (nonatomic, nullable, copy) NSString *groupName;
@property (nonatomic, nullable, copy) NSString *notification;
@property (nonatomic, nullable, copy) NSString *introduction;
@property (nonatomic, nullable, copy) NSString *faceURL;
@property (nonatomic, nullable, copy) NSString *ex;
@end
@interface OIMGroupCreateInfo : NSObject
@property (nonatomic, strong) OIMGroupBaseInfo *groupInfo;
@property (nonatomic, copy) NSArray <NSString *> *memberUserIDs;
@property (nonatomic, copy) NSArray <NSString *> *adminUserIDs;
@property (nonatomic, copy) NSString *ownerUserID;
@end
/// Group Information
///
@interface OIMGroupInfo : OIMGroupBaseInfo
@property (nonatomic, nullable, copy) NSString *groupID;
@property (nonatomic, assign, readonly) NSInteger createTime;
@property (nonatomic, assign, readonly) NSInteger memberCount;
@property (nonatomic, assign, readonly) OIMGroupStatus status;
@property (nonatomic, copy, readonly) NSString *creatorUserID;
@property (nonatomic, copy, readonly) NSString *ownerUserID;
@property (nonatomic, assign) OIMGroupVerificationType needVerification;
@property (nonatomic, assign) OIMAllowType lookMemberInfo;
@property (nonatomic, assign) OIMAllowType applyMemberFriend;
@property (nonatomic, assign) NSInteger notificationUpdateTime;
@property (nonatomic, nullable, copy) NSString *notificationUserID;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,20 @@
//
// OIMGroupInfo.h
// OpenIMSDK
//
// Created by x on 2022/2/11.
//
#import "OIMGroupInfo.h"
@implementation OIMGroupBaseInfo
@end
@implementation OIMGroupCreateInfo
@end
@implementation OIMGroupInfo
@end

View File

@ -0,0 +1,64 @@
//
// OIMGroupMemberInfo.h
// OpenIMSDK
//
// Created by x on 2022/2/11.
//
#import <Foundation/Foundation.h>
#import "OIMDefine.h"
NS_ASSUME_NONNULL_BEGIN
/// Group Member Information
///
@interface OIMGroupMemberBaseInfo : NSObject
@property (nonatomic, nullable, copy) NSString *userID;
@property (nonatomic, assign) OIMGroupMemberRole roleLevel;
@end
/// Group Member Information
///
@interface OIMGroupMemberInfo : OIMGroupMemberBaseInfo
@property (nonatomic, nullable, copy) NSString *groupID;
@property (nonatomic, nullable, copy) NSString *nickname;
@property (nonatomic, nullable, copy) NSString *faceURL;
/**
* Join time
*/
@property (nonatomic, assign) NSInteger joinTime;
/**
* Method of joining
*/
@property (nonatomic, assign) OIMJoinType joinSource;
/**
* Operator's ID
*/
@property (nonatomic, nullable, copy) NSString *operatorUserID;
/**
* Mute end timestamp (in seconds)
*/
@property (nonatomic, assign) NSTimeInterval muteEndTime;
@property (nonatomic, copy) NSString *inviterUserID;
@property (nonatomic, nullable, copy) NSString *ex;
@end
@interface OIMSetGroupMemberInfo : NSObject
@property (nonatomic, nullable, copy) NSString *userID;
@property (nonatomic, nullable, copy) NSString *groupID;
@property (nonatomic, nullable, copy) NSString *nickname;
@property (nonatomic, nullable, copy) NSString *faceURL;
@property (nonatomic, assign) OIMGroupMemberRole roleLevel;
@property (nonatomic, nullable, copy) NSString *ex;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,20 @@
//
// OIMGroupMemberInfo.m
// OpenIMSDK
//
// Created by x on 2022/2/11.
//
#import "OIMGroupMemberInfo.h"
@implementation OIMGroupMemberBaseInfo
@end
@implementation OIMGroupMemberInfo
@end
@implementation OIMSetGroupMemberInfo
@end

View File

@ -0,0 +1,20 @@
//
// OIMLocationElem.h
// OpenIMSDK
//
// Created by x on 2022/2/11.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface OIMLocationElem : NSObject
@property (nonatomic, nullable, copy) NSString *desc;
@property (nonatomic, assign) double longitude;
@property (nonatomic, assign) double latitude;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,15 @@
//
// OIMLocationElem.h
// OpenIMSDK
//
// Created by x on 2022/2/11.
//
#import "OIMLocationElem.h"
@implementation OIMLocationElem
+ (NSDictionary *)mj_replacedKeyFromPropertyName {
return @{@"desc" : @"description"};
}
@end

View File

@ -0,0 +1,23 @@
//
// OIMMergeElem.h
// OpenIMSDK
//
// Created by x on 2022/2/11.
//
#import <Foundation/Foundation.h>
#import "OIMMessageElem.h"
@class OIMMessageInfo;
NS_ASSUME_NONNULL_BEGIN
@interface OIMMergeElem : NSObject
@property (nonatomic, nullable, copy) NSString *title;
@property (nonatomic, nullable, copy) NSArray<NSString *> *abstractList;
@property (nonatomic, nullable, copy) NSArray<OIMMessageInfo *> *multiMessage;
@property (nonatomic, nullable, copy) NSArray<OIMMessageEntity *> *messageEntityList;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,20 @@
//
// OIMMergeElem.h
// OpenIMSDK
//
// Created by x on 2022/2/11.
//
#import "OIMMergeElem.h"
#import <MJExtension/MJExtension.h>
#import "OIMMessageInfo.h"
@implementation OIMMergeElem
+ (NSDictionary *)mj_objectClassInArray
{
return @{@"multiMessage" : [OIMMessageInfo class],
@"messageEntityList" : [OIMMessageEntity class]};
}
@end

View File

@ -0,0 +1,55 @@
//
// OIMMessageElem.h
// OpenIMSDK
//
// Created by x on 2022/7/15.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface OIMMessageEntity : NSObject
@property (nonatomic, copy) NSString *type;
@property (nonatomic, assign) NSInteger offset;
@property (nonatomic, assign) NSInteger length;
@property (nonatomic, copy) NSString *url;
@property (nonatomic, copy) NSString *info;
@end
@interface OIMAdvancedTextElem : NSObject
@property (nonatomic, copy) NSString *text;
@property (nonatomic, copy) NSArray <OIMMessageEntity *> *messageEntityList;
@end
@interface OIMMessageElem : NSObject
@end
@interface OIMTextElem : NSObject
@property (nonatomic, copy) NSString *content;
@end
@interface OIMCardElem : NSObject
@property (nonatomic, copy) NSString *userID;
@property (nonatomic, copy) NSString *nickname;
@property (nonatomic, copy) NSString *faceURL;
@property (nonatomic, copy) NSString *ex;
@end
@interface OIMTypingElem : NSObject
@property (nonatomic, copy) NSString *msgTips;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,38 @@
//
// OIMMessageElem.m
// OpenIMSDK
//
// Created by x on 2022/7/15.
//
#import "OIMMessageElem.h"
#import <MJExtension/MJExtension.h>
@implementation OIMMessageEntity
@end
@implementation OIMAdvancedTextElem
+ (NSDictionary *)mj_objectClassInArray
{
return @{@"messageEntityList" : [OIMMessageEntity class]};
}
@end
@implementation OIMMessageElem
@end
@implementation OIMTextElem
@end
@implementation OIMCardElem
@end
@implementation OIMTypingElem
@end

View File

@ -0,0 +1,213 @@
//
// OIMMessageInfo.h
// OpenIMSDK
//
// Created by x on 2022/2/11.
//
#import <Foundation/Foundation.h>
#import "OIMPictureElem.h"
#import "OIMSoundElem.h"
#import "OIMVideoElem.h"
#import "OIMFileElem.h"
#import "OIMMergeElem.h"
#import "OIMAtElem.h"
#import "OIMLocationElem.h"
#import "OIMCustomElem.h"
#import "OIMQuoteElem.h"
#import "OIMNotificationElem.h"
#import "OIMFaceElem.h"
#import "OIMAttachedInfoElem.h"
#import "OIMDefine.h"
#import "OIMMessageElem.h"
NS_ASSUME_NONNULL_BEGIN
@interface OIMOfflinePushInfo : NSObject
@property (nonatomic, nullable, copy) NSString *title;
@property (nonatomic, nullable, copy) NSString *desc;
@property (nonatomic, nullable, copy) NSString *iOSPushSound;
@property (nonatomic, assign) BOOL iOSBadgeCount;
@property (nonatomic, nullable, copy) NSString *operatorUserID;
@property (nonatomic, nullable, copy) NSString *ex;
@end
/// Message Model
///
@interface OIMMessageInfo : NSObject
@property (nonatomic, nullable, copy) NSString *clientMsgID;
@property (nonatomic, nullable, copy) NSString *serverMsgID;
@property (nonatomic, assign) NSTimeInterval createTime;
@property (nonatomic, assign) NSTimeInterval sendTime;
@property (nonatomic, assign) OIMConversationType sessionType;
@property (nonatomic, nullable, copy) NSString *sendID;
@property (nonatomic, nullable, copy) NSString *recvID;
@property (nonatomic, nullable, copy) NSString *handleMsg;
@property (nonatomic, assign) OIMMessageLevel msgFrom;
@property (nonatomic, assign) OIMMessageContentType contentType;
@property (nonatomic, assign) OIMPlatform senderPlatformID;
@property (nonatomic, nullable, copy) NSString *senderNickname;
@property (nonatomic, nullable, copy) NSString *senderFaceUrl;
@property (nonatomic, nullable, copy) NSString *groupID;
@property (nonatomic, nullable, copy) NSString *content;
/**
* Message unique sequence number
*/
@property (nonatomic, assign) NSInteger seq;
@property (nonatomic, assign) BOOL isRead;
@property (nonatomic, assign) OIMMessageStatus status;
@property (nonatomic, nullable, copy) NSString *attachedInfo;
@property (nonatomic, nullable, copy) NSString *localEx;
@property (nonatomic, nullable, copy) NSString *ex;
@property (nonatomic, strong) OIMOfflinePushInfo *offlinePush;
@property (nonatomic, nullable, strong) OIMTextElem *textElem;
@property (nonatomic, nullable, strong) OIMCardElem *cardElem;
@property (nonatomic, nullable, strong) OIMPictureElem *pictureElem;
@property (nonatomic, nullable, strong) OIMSoundElem *soundElem;
@property (nonatomic, nullable, strong) OIMVideoElem *videoElem;
@property (nonatomic, nullable, strong) OIMFileElem *fileElem;
@property (nonatomic, nullable, strong) OIMMergeElem *mergeElem;
@property (nonatomic, nullable, strong) OIMAtTextElem *atTextElem;
@property (nonatomic, nullable, strong) OIMLocationElem *locationElem;
@property (nonatomic, nullable, strong) OIMQuoteElem *quoteElem;
@property (nonatomic, nullable, strong) OIMCustomElem *customElem;
@property (nonatomic, nullable, strong) OIMNotificationElem *notificationElem;
@property (nonatomic, nullable, strong) OIMFaceElem *faceElem;
@property (nonatomic, nullable, strong) OIMAttachedInfoElem *attachedInfoElem;
@property (nonatomic, nullable, strong) OIMAdvancedTextElem *advancedTextElem;
@property (nonatomic, nullable, strong) OIMTypingElem *typingElem;
@property (nonatomic, assign) NSTimeInterval hasReadTime;
@property (nonatomic, assign) BOOL isReact;
@property (nonatomic, assign) BOOL isExternalExtensions;
@end
@interface OIMReceiptInfo : NSObject
/**
* User ID - for one-on-one chat
*/
@property (nonatomic, nullable, copy) NSString *userID;
/**
* Group ID - for group chat
*/
@property (nonatomic, nullable, copy) NSString *groupID;
/**
* Read message IDs
*/
@property (nonatomic, nullable, copy) NSArray<NSString *> *msgIDList;
/**
* Reading time
*/
@property (nonatomic, assign) NSInteger readTime;
@property (nonatomic, assign) OIMMessageLevel msgFrom;
@property (nonatomic, assign) OIMMessageContentType contentType;
@property (nonatomic, assign) OIMConversationType sessionType;
@end
@interface OIMMessageRevokedInfo : NSObject
/**
* ID of the revoker
*/
@property (nonatomic, copy) NSString *revokerID;
@property (nonatomic, copy) NSString *revokerNickname;
/**
* Revoker's role, e.g., group owner, group administrator
*/
@property (nonatomic, assign) OIMGroupMemberRole revokerRole;
@property (nonatomic, copy) NSString *clientMsgID;
@property (nonatomic, assign) NSTimeInterval revokeTime;
@property (nonatomic, assign) NSTimeInterval sourceMessageSendTime;
@property (nonatomic, copy) NSString *sourceMessageSendID;
@property (nonatomic, copy) NSString *sourceMessageSenderNickname;
@property (nonatomic, assign) OIMConversationType sessionType;
@property (nonatomic, copy) NSString *ex;
@end
@interface OIMKeyValue: NSObject
@property (nonatomic, copy) NSString *errMsg;
@property (nonatomic, assign) NSInteger errCode;
@property (nonatomic, copy) NSString *typeKey;
@property (nonatomic, copy) NSString *value;
@property (nonatomic, assign) NSTimeInterval latestUpdateTime;
@end
@interface OIMKeyValues: NSObject
@property (nonatomic, copy) NSString *errMsg;
@property (nonatomic, assign) NSInteger errCode;
@property (nonatomic, copy) NSString *clientMsgID;
@property (nonatomic, copy) NSDictionary<NSString *, OIMKeyValue *> *reactionExtensionList;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,64 @@
//
// OIMMessageInfo.m
// OpenIMSDK
//
// Created by x on 2022/2/11.
//
#import "OIMMessageInfo.h"
#import <MJExtension/MJExtension.h>
@implementation OIMOfflinePushInfo
- (instancetype)init {
self = [super init];
if (self) {
self.title = @"";
self.desc = @"";
self.ex = @"";
self.iOSPushSound = @"";
self.iOSBadgeCount = YES;
}
return self;
}
@end
@implementation OIMMessageInfo
- (instancetype)init {
self = [super init];
if (self) {
self.offlinePush = [OIMOfflinePushInfo new];
self.status = OIMMessageStatusUndefine;
}
return self;
}
- (NSTimeInterval)hasReadTime {
if (_hasReadTime == 0) {
_hasReadTime = _attachedInfoElem.hasReadTime;
}
return _hasReadTime;
}
@end
@implementation OIMReceiptInfo
@end
@implementation OIMMessageRevokedInfo
@end
@implementation OIMKeyValue
@end
@implementation OIMKeyValues
@end

View File

@ -0,0 +1,39 @@
//
// OIMNotificationElem.h
// OpenIMSDK
//
// Created by x on 2022/2/21.
//
#import <Foundation/Foundation.h>
#import "OIMGroupMemberInfo.h"
#import "OIMGroupInfo.h"
NS_ASSUME_NONNULL_BEGIN
@interface OIMNotificationElem : NSObject
@property (nonatomic, nullable, copy) NSString *detail;
/**
* The following fields are decoded from the 'detail' field
*/
@property (nonatomic, nullable, strong, readonly) OIMGroupMemberInfo *opUser;
@property (nonatomic, nullable, strong, readonly) OIMGroupMemberInfo *quitUser;
@property (nonatomic, nullable, strong, readonly) OIMGroupMemberInfo *entrantUser;
/**
* Information about the new group owner after a group change
*/
@property (nonatomic, nullable, strong, readonly) OIMGroupMemberInfo *groupNewOwner;
@property (nonatomic, nullable, strong, readonly) OIMGroupInfo *group;
@property (nonatomic, nullable, strong, readonly) NSArray <OIMGroupMemberInfo *> *kickedUserList;
@property (nonatomic, nullable, strong, readonly) NSArray <OIMGroupMemberInfo *> *invitedUserList;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,39 @@
//
// OIMNotificationElem.m
// OpenIMSDK
//
// Created by x on 2022/2/21.
//
#import "OIMNotificationElem.h"
#import <MJExtension/MJExtension.h>
@implementation OIMNotificationElem
+ (NSDictionary *)mj_replacedKeyFromPropertyName {
return @{@"groupNewOwner" : @"newGroupOwner"};
}
+ (NSDictionary *)mj_objectClassInArray {
return @{@"kickedUserList" : [OIMGroupMemberInfo class],
@"invitedUserList": [OIMGroupMemberInfo class]
};
}
- (void)setDetail:(NSString *)detail {
_detail = detail;
if (detail.length > 0) {
OIMNotificationElem *elem = [OIMNotificationElem mj_objectWithKeyValues:detail];
_group = elem.group;
_opUser = elem.opUser;
_quitUser = elem.quitUser;
_entrantUser = elem.entrantUser;
_kickedUserList = elem.kickedUserList;
_invitedUserList = elem.invitedUserList;
_groupNewOwner = elem.groupNewOwner;
}
}
@end

View File

@ -0,0 +1,69 @@
//
// OIMPictureElem.h
// OpenIMSDK
//
// Created by x on 2022/2/14.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface OIMPictureInfo : NSObject
/**
* Unique ID, can be left unset
*/
@property (nonatomic, nullable, copy) NSString *uuID;
/**
* Image type, can be left unset
*/
@property (nonatomic, nullable, copy) NSString *type;
/**
* Image size
*/
@property (nonatomic, assign) NSInteger size;
/**
* Image width
*/
@property (nonatomic, assign) CGFloat width;
/**
* Image height
*/
@property (nonatomic, assign) CGFloat height;
/**
* Image OSS address
*/
@property (nonatomic, copy) NSString *url;
@end
@interface OIMPictureElem : NSObject
/**
* Local resource path
*/
@property (nonatomic, nullable, copy) NSString *sourcePath;
/**
* Local image details
*/
@property (nonatomic, nullable, strong) OIMPictureInfo *sourcePicture;
/**
* Big image details
*/
@property (nonatomic, nullable, strong) OIMPictureInfo *bigPicture;
/**
* Thumbnail image details
*/
@property (nonatomic, nullable, strong) OIMPictureInfo *snapshotPicture;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,16 @@
//
// OIMPictureElem.h
// OpenIMSDK
//
// Created by x on 2022/2/14.
//
#import "OIMPictureElem.h"
@implementation OIMPictureInfo
@end
@implementation OIMPictureElem
@end

View File

@ -0,0 +1,23 @@
//
// OIMQuoteElem.h
// OpenIMSDK
//
// Created by x on 2022/2/11.
//
#import <Foundation/Foundation.h>
#import "OIMMessageElem.h"
@class OIMMessageInfo;
NS_ASSUME_NONNULL_BEGIN
@interface OIMQuoteElem : NSObject
@property (nonatomic, nullable, copy) NSString *text;
@property (nonatomic, nullable, strong) OIMMessageInfo *quoteMessage;
@property (nonatomic, nullable, copy) NSArray <OIMMessageEntity *> *messageEntityList;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,17 @@
//
// OIMQuoteElem.h
// OpenIMSDK
//
// Created by x on 2022/2/11.
//
#import "OIMQuoteElem.h"
@implementation OIMQuoteElem
+ (NSDictionary *)mj_objectClassInArray
{
return @{@"messageEntityList" : [OIMMessageEntity class]};
}
@end

View File

@ -0,0 +1,161 @@
//
// OIMSearchParam.h
// OpenIMSDK
//
// Created by x on 2022/2/17.
//
#import <Foundation/Foundation.h>
#import "OIMDefine.h"
@class OIMMessageInfo;
NS_ASSUME_NONNULL_BEGIN
@interface OIMSearchParam : NSObject
/**
* Conversation ID, if empty, it's a global search
*/
@property (nonatomic, copy) NSString *conversationID;
/**
* Search keyword list, currently supports only one keyword search
*/
@property (nonatomic, strong) NSArray *keywordList;
/**
* Keyword match mode, 1 means AND, 2 means OR (currently unused)
*/
@property (nonatomic, assign) NSInteger keywordListMatchType;
/**
* Specify the list of sender user IDs (currently unused)
*/
@property (nonatomic, nullable, strong) NSArray *senderUserIDList;
/**
* Message type list
*/
@property (nonatomic, nullable, strong) NSArray *messageTypeList;
/**
* Search start time point. Default is 0, meaning search from now. UTC timestamp, unit: seconds
*/
@property (nonatomic, assign) NSInteger searchTimePosition;
/**
* Time range from the start time point, in seconds. Default is 0, meaning no time limit. Provide 24x60x60 to represent the past day.
*/
@property (nonatomic, assign) NSInteger searchTimePeriod;
/**
* Current page number, starting from the first page (1). It's invalid when conversationID is empty, i.e., in the global search context.
*/
@property (nonatomic, assign) NSInteger pageIndex;
/**
* Number of items per page. It's invalid when conversationID is empty, i.e., in the global search context.
*/
@property (nonatomic, assign) NSInteger count;
@end
// For group search
@interface OIMSearchGroupParam : NSObject
/**
* Search keywords, currently supports only one keyword (must not be empty)
*/
@property (nonatomic, copy) NSArray *keywordList;
/**
* Whether to search for group IDs based on keywords (note: both cannot be false at the same time). Default is false.
*/
@property (nonatomic, assign) BOOL isSearchGroupID;
/**
* Whether to search for group names based on keywords. Default is false.
*/
@property (nonatomic, assign) BOOL isSearchGroupName;
@end
/// For friends search
///
@interface OIMSearchFriendsParam : NSObject
/**
* Search keywords, currently supports only one keyword (must not be empty)
*/
@property (nonatomic, copy) NSArray *keywordList;
/**
* Whether to search for user IDs based on keywords
*/
@property (nonatomic, assign) BOOL isSearchUserID;
/**
* Whether to search for nicknames based on keywords. Default is false.
*/
@property (nonatomic, assign) BOOL isSearchNickname;
/**
* Whether to search for remarks based on keywords. Default is false.
*/
@property (nonatomic, assign) BOOL isSearchRemark;
@end
/// For chat history search
///
@interface OIMGetMessageOptions : NSObject
@property (nonatomic, copy, nullable) NSString *userID;
@property (nonatomic, copy, nullable) NSString *groupID;
/**
* Conversation ID; if not empty, retrieve messages by conversation ID, otherwise use userID and groupID
*/
@property (nonatomic, copy, nullable) NSString *conversationID;
/**
* Start message clientMsgID
*/
@property (nonatomic, copy, nullable) NSString *startClientMsgID;
@property (nonatomic, assign) NSInteger count;
@end
@interface OIMGetAdvancedHistoryMessageListParam : OIMGetMessageOptions
@property (nonatomic, assign) OIMGetHistoryViewType viewType;
@end
@interface OIMFindMessageListParam : NSObject
@property (nonatomic, copy) NSString *conversationID;
@property (nonatomic, copy) NSArray <NSString *> *clientMsgIDList;
@end
/// For group members search
///
@interface OIMSearchGroupMembersParam : NSObject
@property (nonatomic, copy) NSString *groupID;
@property (nonatomic, copy) NSArray *keywordList;
/**
* Whether to search user IDs based on keywords
*/
@property (nonatomic, assign) BOOL isSearchUserID;
/**
* Whether to search member nicknames based on keywords. Default is false.
*/
@property (nonatomic, assign) BOOL isSearchMemberNickname;
@property (nonatomic, assign) NSInteger offset;
@property (nonatomic, assign) NSInteger count;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,50 @@
//
// OIMSearchParam.m
// OpenIMSDK
//
// Created by x on 2022/2/17.
//
#import "OIMSearchParam.h"
#import <MJExtension/MJExtension.h>
#import "OIMMessageInfo.h"
@implementation OIMSearchParam
- (instancetype)init {
self = [super init];
if (self) {
_senderUserIDList = @[];
_messageTypeList = @[];
}
return self;
}
@end
@implementation OIMSearchGroupParam
@end
@implementation OIMGetMessageOptions
@end
@implementation OIMGetAdvancedHistoryMessageListParam
@end
@implementation OIMSearchFriendsParam
@end
@implementation OIMFindMessageListParam
@end
@implementation OIMSearchGroupMembersParam
@end

View File

@ -0,0 +1,67 @@
//
// OIMSearchResultInfo.h
// OpenIMSDK
//
// Created by x on 2022/2/17.
//
#import <Foundation/Foundation.h>
#import "OIMDefine.h"
@class OIMMessageInfo;
NS_ASSUME_NONNULL_BEGIN
@interface OIMSearchResultItemInfo : NSObject
/**
* Conversation ID
*/
@property (nonatomic, copy) NSString *conversationID;
/**
* Number of messages in this conversation
*/
@property (nonatomic, assign) NSInteger messageCount;
@property (nonatomic, assign) OIMConversationType conversationType;
@property (nonatomic, copy) NSString *showName;
@property (nonatomic, copy) NSString *faceURL;
/**
* List of OIMMessageInfo
*/
@property (nonatomic, copy) NSArray <OIMMessageInfo *> *messageList;
@end
@interface OIMSearchResultInfo : NSObject
/**
* Total number of messages obtained
*/
@property (nonatomic, assign) NSInteger totalCount;
/**
* Search results
*/
@property (nonatomic, copy) NSArray <OIMSearchResultItemInfo *> *searchResultItems;
/**
* Only applicable to the callback result of the findMessageList function
*/
@property (nonatomic, copy) NSArray <OIMSearchResultItemInfo *> *findResultItems;
@end
@interface OIMGetAdvancedHistoryMessageListInfo : NSObject
@property (nonatomic, assign) BOOL isEnd;
@property (nonatomic, assign) NSInteger lastMinSeq;
@property (nonatomic, assign) NSInteger errCode;
@property (nonatomic, copy) NSString *errMsg;
@property (nonatomic, copy) NSArray <OIMMessageInfo *> *messageList;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,39 @@
//
// OIMSearchResultInfo.m
// OpenIMSDK
//
// Created by x on 2022/2/17.
//
#import "OIMSearchResultInfo.h"
#import <MJExtension/MJExtension.h>
#import "OIMMessageInfo.h"
@implementation OIMSearchResultItemInfo
+ (NSDictionary *)mj_objectClassInArray
{
return @{@"messageList" : [OIMMessageInfo class]};
}
@end
@implementation OIMSearchResultInfo
+ (NSDictionary *)mj_objectClassInArray
{
return @{@"searchResultItems" : [OIMSearchResultItemInfo class],
@"findResultItems" : [OIMSearchResultItemInfo class]
};
}
@end
@implementation OIMGetAdvancedHistoryMessageListInfo
+ (NSDictionary *)mj_objectClassInArray
{
return @{@"messageList" : [OIMMessageInfo class]};
}
@end

View File

@ -0,0 +1,30 @@
//
// OIMSimpleRequstInfo.h
// OpenIMSDK
//
// Created by x on 2022/2/14.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface OIMSimpleRequstInfo : NSObject
@property (nonatomic, nullable, copy) NSString *toUserID;
/**
* Only for adding friend requests
*/
@property (nonatomic, nullable, copy) NSString *reqMsg;
/**
* Only for setting friend remarks
*/
@property (nonatomic, nullable, copy) NSString *remark;
/**
* Only for approving a friend request from someone
*/
@property (nonatomic, nullable, copy) NSString *handleMsg;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,12 @@
//
// OIMSimpleRequstInfo.m
// OpenIMSDK
//
// Created by x on 2022/2/14.
//
#import "OIMSimpleRequstInfo.h"
@implementation OIMSimpleRequstInfo
@end

View File

@ -0,0 +1,22 @@
//
// OIMSimpleResultInfo.h
// OpenIMSDK
//
// Created by x on 2022/2/14.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface OIMSimpleResultInfo : NSObject
@property (nonatomic, nullable, copy) NSString *userID;
/**
* For checkFriend: a result of 1 indicates a friend (and not in the blacklist).
*/
@property (nonatomic, assign) NSInteger result;
@end
NS_ASSUME_NONNULL_END

Some files were not shown because too many files have changed in this diff Show More