From 624c86662f9ba99e86799ab4348e3f253be55ef3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Toni=20Ca=CC=81rdenas?= <toni@tcardenas.me>
Date: Thu, 7 Apr 2016 22:10:48 +0200
Subject: [PATCH] Rearrange types relationships to avoid ambiguities.

Previously, we had some situations in which, for convenience, we were
inheriting rather than composing (RealtimeChannel inheriting from
RestChannel). This was causing problems in places where some parent
class implemented `method:(A)a` while a child class was implementing
`method:(B)b`. Swift 2.2 doesn't let you do this, so it's necessary for
that, but it's also a good idea for Swift <2.2 if only for code
organization and soundness.

Also added some changes in the test Swift code for forwards
compatibility.
---
 Ably.xcodeproj/project.pbxproj       | 10 +++-
 Source/ARTChannel.h                  |  1 -
 Source/ARTChannel.m                  |  5 --
 Source/ARTClientOptions.m            |  1 +
 Source/ARTPresence+Private.h         |  1 +
 Source/ARTPresence.h                 | 24 +--------
 Source/ARTPresence.m                 | 72 --------------------------
 Source/ARTRealtimeChannel+Private.h  |  2 +
 Source/ARTRealtimeChannel.h          |  7 +--
 Source/ARTRealtimeChannel.m          | 10 ++--
 Source/ARTRealtimePresence+Private.h | 20 ++++++++
 Source/ARTRealtimePresence.h         |  9 ++--
 Source/ARTRealtimePresence.m         | 76 +++++++++++++--------------
 Source/ARTRestChannel+Private.h      |  2 +
 Source/ARTRestChannel.h              |  2 +-
 Source/ARTRestChannel.m              |  6 ++-
 Source/ARTRestChannels.m             |  1 +
 Source/ARTRestPresence+Private.h     | 24 +++++++++
 Source/ARTRestPresence.h             | 19 ++++++-
 Source/ARTRestPresence.m             | 77 +++++++++++++++++++++++-----
 Spec/RealtimeClientChannel.swift     |  6 ++-
 Spec/RealtimeClientConnection.swift  |  8 +--
 Spec/RestClientChannel.swift         | 11 ++--
 Spec/RestClientPresence.swift        | 46 +++++++++++++++++
 Tests/ARTRestChannelHistoryTest.m    | 16 +++---
 Tests/ARTRestChannelPublishTest.m    |  2 +-
 26 files changed, 267 insertions(+), 191 deletions(-)
 create mode 100644 Source/ARTRealtimePresence+Private.h
 create mode 100644 Source/ARTRestPresence+Private.h

diff --git a/Ably.xcodeproj/project.pbxproj b/Ably.xcodeproj/project.pbxproj
index ada996cb9..c1da397d7 100644
--- a/Ably.xcodeproj/project.pbxproj
+++ b/Ably.xcodeproj/project.pbxproj
@@ -135,8 +135,8 @@
 		D7CEF12D1C8D821D004FB242 /* ARTRealtimeChannels+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = D7CEF12C1C8D821D004FB242 /* ARTRealtimeChannels+Private.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		D7CEF1321C8DD3BC004FB242 /* RealtimeClientPresence.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7CEF1311C8DD3BC004FB242 /* RealtimeClientPresence.swift */; };
 		D7D29B421BE3DEB300374295 /* ARTConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = D7D29B411BE3DEB300374295 /* ARTConnection.m */; };
-		D7D5A69C1CA40C350071BD6D /* ARTConnectionDetails+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = D7D5A69B1CA40C350071BD6D /* ARTConnectionDetails+Private.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		D7D5A69A1CA3D9040071BD6D /* ARTAuthOptions+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = D7D5A6991CA3D9040071BD6D /* ARTAuthOptions+Private.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		D7D5A69C1CA40C350071BD6D /* ARTConnectionDetails+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = D7D5A69B1CA40C350071BD6D /* ARTConnectionDetails+Private.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		D7D8F8211BC2BE16009718F2 /* ARTAuthOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = D7D8F81F1BC2BE15009718F2 /* ARTAuthOptions.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		D7D8F8221BC2BE16009718F2 /* ARTAuthOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = D7D8F8201BC2BE15009718F2 /* ARTAuthOptions.m */; };
 		D7D8F8251BC2C691009718F2 /* ARTTokenDetails.h in Headers */ = {isa = PBXBuildFile; fileRef = D7D8F8231BC2C691009718F2 /* ARTTokenDetails.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -160,6 +160,7 @@
 		EB503C881C7E4A090053AF00 /* ARTClientOptions+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = EB503C871C7E4A090053AF00 /* ARTClientOptions+Private.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		EB503C8A1C7F1FE40053AF00 /* ARTLog+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = EB503C891C7F1FE40053AF00 /* ARTLog+Private.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		EB5E058D1C77027600A48B39 /* ARTCrypto+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = EB5E058C1C77027600A48B39 /* ARTCrypto+Private.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		EB7617721CB6CBFF00D0981E /* ARTRealtimePresence+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = EB7617711CB6CBFE00D0981E /* ARTRealtimePresence+Private.h */; };
 		EB7913A81C6E54C3000ABF9B /* Crypto.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB7913A71C6E54C3000ABF9B /* Crypto.swift */; };
 		EB82F8511C59D29B00661917 /* ARTDataEncoder.h in Headers */ = {isa = PBXBuildFile; fileRef = EB3239461C59AB2C00892664 /* ARTDataEncoder.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		EB82F8521C59D30500661917 /* ARTDataEncoder.m in Sources */ = {isa = PBXBuildFile; fileRef = EB3239421C59AB0400892664 /* ARTDataEncoder.m */; };
@@ -357,8 +358,8 @@
 		D7CEF1311C8DD3BC004FB242 /* RealtimeClientPresence.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RealtimeClientPresence.swift; sourceTree = "<group>"; };
 		D7D29B401BE3DD0600374295 /* ARTConnection.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ARTConnection.h; sourceTree = "<group>"; };
 		D7D29B411BE3DEB300374295 /* ARTConnection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTConnection.m; sourceTree = "<group>"; };
-		D7D5A69B1CA40C350071BD6D /* ARTConnectionDetails+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ARTConnectionDetails+Private.h"; sourceTree = "<group>"; };
 		D7D5A6991CA3D9040071BD6D /* ARTAuthOptions+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ARTAuthOptions+Private.h"; sourceTree = "<group>"; };
+		D7D5A69B1CA40C350071BD6D /* ARTConnectionDetails+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ARTConnectionDetails+Private.h"; sourceTree = "<group>"; };
 		D7D8F81F1BC2BE15009718F2 /* ARTAuthOptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTAuthOptions.h; sourceTree = "<group>"; };
 		D7D8F8201BC2BE15009718F2 /* ARTAuthOptions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTAuthOptions.m; sourceTree = "<group>"; };
 		D7D8F8231BC2C691009718F2 /* ARTTokenDetails.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTTokenDetails.h; sourceTree = "<group>"; };
@@ -383,6 +384,8 @@
 		EB503C871C7E4A090053AF00 /* ARTClientOptions+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ARTClientOptions+Private.h"; sourceTree = "<group>"; };
 		EB503C891C7F1FE40053AF00 /* ARTLog+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ARTLog+Private.h"; sourceTree = "<group>"; };
 		EB5E058C1C77027600A48B39 /* ARTCrypto+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ARTCrypto+Private.h"; sourceTree = "<group>"; };
+		EB7617701CB6C18C00D0981E /* ARTRestPresence+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ARTRestPresence+Private.h"; sourceTree = "<group>"; };
+		EB7617711CB6CBFE00D0981E /* ARTRealtimePresence+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ARTRealtimePresence+Private.h"; sourceTree = "<group>"; };
 		EB7913A71C6E54C3000ABF9B /* Crypto.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Crypto.swift; sourceTree = "<group>"; };
 		EB89D4021C61C1A4007FA5B7 /* ARTRestChannels.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTRestChannels.h; sourceTree = "<group>"; };
 		EB89D4031C61C1A4007FA5B7 /* ARTRestChannels.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTRestChannels.m; sourceTree = "<group>"; };
@@ -586,6 +589,7 @@
 				D7C1B8781BBF5F460087B55F /* ARTAuth+Private.h */,
 				96BF616F1A35FB7C004CF2B3 /* ARTAuth.m */,
 				D7F1D3711BF4DE07001A4B5E /* ARTRestPresence.h */,
+				EB7617701CB6C18C00D0981E /* ARTRestPresence+Private.h */,
 				D7F1D3721BF4DE07001A4B5E /* ARTRestPresence.m */,
 				EB89D4021C61C1A4007FA5B7 /* ARTRestChannels.h */,
 				EB89D4031C61C1A4007FA5B7 /* ARTRestChannels.m */,
@@ -608,6 +612,7 @@
 				D7D5A69B1CA40C350071BD6D /* ARTConnectionDetails+Private.h */,
 				D7B17EE21C07208B00A6958E /* ARTConnectionDetails.m */,
 				D7F1D3751BF4DE72001A4B5E /* ARTRealtimePresence.h */,
+				EB7617711CB6CBFE00D0981E /* ARTRealtimePresence+Private.h */,
 				D7F1D3761BF4DE72001A4B5E /* ARTRealtimePresence.m */,
 				D746AE321BBC29EB003ECEF8 /* Transport */,
 				D746AE451BBD6FE9003ECEF8 /* ARTQueuedMessage.h */,
@@ -783,6 +788,7 @@
 				EB20F8D71C653F2300EF3978 /* ARTPresence+Private.h in Headers */,
 				D7F1D3771BF4DE72001A4B5E /* ARTRealtimePresence.h in Headers */,
 				1C578E1F1B3435CA00EF46EC /* ARTFallback.h in Headers */,
+				EB7617721CB6CBFF00D0981E /* ARTRealtimePresence+Private.h in Headers */,
 				D7D5A69C1CA40C350071BD6D /* ARTConnectionDetails+Private.h in Headers */,
 				96E408471A3895E800087F77 /* ARTWebSocketTransport.h in Headers */,
 				EB503C8A1C7F1FE40053AF00 /* ARTLog+Private.h in Headers */,
diff --git a/Source/ARTChannel.h b/Source/ARTChannel.h
index c7b47bf4f..be05dccc2 100644
--- a/Source/ARTChannel.h
+++ b/Source/ARTChannel.h
@@ -34,7 +34,6 @@ ART_ASSUME_NONNULL_BEGIN
 - (void)publish:(__GENERIC(NSArray, ARTMessage *) *)messages callback:(art_nullable void (^)(ARTErrorInfo *__art_nullable error))callback;
 
 - (void)history:(void(^)(__GENERIC(ARTPaginatedResult, ARTMessage *) *__art_nullable result, ARTErrorInfo *__art_nullable error))callback;
-- (BOOL)history:(art_nullable ARTDataQuery *)query callback:(void(^)(__GENERIC(ARTPaginatedResult, ARTMessage *) *__art_nullable result, ARTErrorInfo *__art_nullable error))callback error:(NSError *__art_nullable *__art_nullable)errorPtr;
 
 @end
 
diff --git a/Source/ARTChannel.m b/Source/ARTChannel.m
index b150bb81c..5248fadc4 100644
--- a/Source/ARTChannel.m
+++ b/Source/ARTChannel.m
@@ -82,12 +82,7 @@ - (ARTMessage *)encodeMessageIfNeeded:(ARTMessage *)message {
 }
 
 - (void)history:(void (^)(__GENERIC(ARTPaginatedResult, ARTMessage *) *, ARTErrorInfo *))callback {
-    [self history:[[ARTDataQuery alloc] init] callback:callback error:nil];
-}
-
-- (BOOL)history:(ARTDataQuery *)query callback:(void (^)(__GENERIC(ARTPaginatedResult, ARTMessage *) *, ARTErrorInfo *))callback error:(NSError **)errorPtr {
     NSAssert(false, @"-[%@ %@] should always be overriden.", self.class, NSStringFromSelector(_cmd));
-    return NO;
 }
 
 - (void)internalPostMessages:(id)data callback:(void (^)(ARTErrorInfo *__art_nullable error))callback {
diff --git a/Source/ARTClientOptions.m b/Source/ARTClientOptions.m
index c08368460..e392546a8 100644
--- a/Source/ARTClientOptions.m
+++ b/Source/ARTClientOptions.m
@@ -87,6 +87,7 @@ - (id)copyWithZone:(NSZone *)zone {
     options.environment = self.environment;
     options.tls = self.tls;
     options.logLevel = self.logLevel;
+    options.logHandler = self.logHandler;
     options.suspendedRetryTimeout = self.suspendedRetryTimeout;
     options.disconnectedRetryTimeout = self.disconnectedRetryTimeout;
     options.httpMaxRetryCount = self.httpMaxRetryCount;
diff --git a/Source/ARTPresence+Private.h b/Source/ARTPresence+Private.h
index fca2ec59e..d81095a63 100644
--- a/Source/ARTPresence+Private.h
+++ b/Source/ARTPresence+Private.h
@@ -10,6 +10,7 @@
 #define ARTPresence_Private_h
 
 #import "ARTPresence.h"
+#import "ARTChannel.h"
 
 @interface ARTPresenceQuery ()
 
diff --git a/Source/ARTPresence.h b/Source/ARTPresence.h
index 4666a90c6..c5fb33570 100644
--- a/Source/ARTPresence.h
+++ b/Source/ARTPresence.h
@@ -9,35 +9,13 @@
 #import <Foundation/Foundation.h>
 #import "ARTTypes.h"
 #import "ARTPresenceMessage.h"
-
-@class ARTChannel;
-@class __GENERIC(ARTPaginatedResult, ItemType);
-@class ARTDataQuery;
+#import "ARTPaginatedResult.h"
 
 ART_ASSUME_NONNULL_BEGIN
 
-@interface ARTPresenceQuery : NSObject
-
-@property (nonatomic, readwrite) NSUInteger limit;
-@property (nonatomic, strong, readwrite) NSString *clientId;
-@property (nonatomic, strong, readwrite) NSString *connectionId;
-
-- (instancetype)init;
-- (instancetype)initWithClientId:(NSString *__art_nullable)clientId connectionId:(NSString *__art_nullable)connectionId;
-- (instancetype)initWithLimit:(NSUInteger)limit clientId:(NSString *__art_nullable)clientId connectionId:(NSString *__art_nullable)connectionId;
-
-@end
-
-/// A class that provides access to presence operations and state for the associated Channel.
 @interface ARTPresence : NSObject
 
-/// Get the presence state for one channel.
-- (void)get:(void (^)(__GENERIC(ARTPaginatedResult, ARTPresenceMessage *) *__art_nullable result, ARTErrorInfo *__art_nullable error))callback;
-- (BOOL)get:(ARTPresenceQuery *)query callback:(void (^)(__GENERIC(ARTPaginatedResult, ARTPresenceMessage *) *__art_nullable result, ARTErrorInfo *__art_nullable error))callback error:(NSError *__art_nullable *__art_nullable)errorPtr;
-
-/// Obtain recent presence history for one channel.
 - (void)history:(void(^)(__GENERIC(ARTPaginatedResult, ARTPresenceMessage *) *__art_nullable result, ARTErrorInfo *__art_nullable error))callback;
-- (BOOL)history:(art_nullable ARTDataQuery *)query callback:(void(^)(__GENERIC(ARTPaginatedResult, ARTPresenceMessage *) *__art_nullable result, ARTErrorInfo *__art_nullable error))callback error:(NSError *__art_nullable *__art_nullable)errorPtr;
 
 @end
 
diff --git a/Source/ARTPresence.m b/Source/ARTPresence.m
index b181b94db..fe2fb4d13 100644
--- a/Source/ARTPresence.m
+++ b/Source/ARTPresence.m
@@ -8,82 +8,10 @@
 
 #import "ARTPresence.h"
 
-#import "ARTChannel.h"
-#import "ARTDataQuery.h"
-
-@implementation ARTPresenceQuery
-
-- (instancetype)init {
-    return [self initWithClientId:nil connectionId:nil];
-}
-
-- (instancetype)initWithClientId:(NSString *)clientId connectionId:(NSString *)connectionId {
-    return [self initWithLimit:100 clientId:clientId connectionId:connectionId];
-}
-
-- (instancetype)initWithLimit:(NSUInteger)limit clientId:(NSString *)clientId connectionId:(NSString *)connectionId {
-    self = [super init];
-    if (self) {
-        _limit = limit;
-        _clientId = clientId;
-        _connectionId = connectionId;
-    }
-    return self;
-}
-
-- (NSMutableArray *)asQueryItems {
-    NSMutableArray *items = [NSMutableArray array];
-
-    if (self.clientId) {
-        [items addObject:[NSURLQueryItem queryItemWithName:@"clientId" value:self.clientId]];
-    }
-    if (self.connectionId) {
-        [items addObject:[NSURLQueryItem queryItemWithName:@"connectionId" value:self.connectionId]];
-    }
-
-    [items addObject:[NSURLQueryItem queryItemWithName:@"limit" value:[NSString stringWithFormat:@"%lu", (unsigned long)self.limit]]];
-
-    return items;
-}
-
-@end
-
-@interface ARTPresence () {
-    __weak ARTChannel *_channel;
-}
-
-@end
-
 @implementation ARTPresence
 
-- (instancetype) initWithChannel:(ARTChannel *) channel {
-    if (self = [super init]) {
-        _channel = channel;
-    }
-    return self;
-}
-
-- (ARTChannel *)getChannel {
-    return _channel;
-}
-
-
-- (void)get:(void (^)(__GENERIC(ARTPaginatedResult, ARTPresenceMessage *) *result, ARTErrorInfo *error))callback {
-    [self get:[[ARTPresenceQuery alloc] init] callback:callback error:nil];
-}
-
-- (BOOL)get:(ARTPresenceQuery *)query callback:(void (^)(ARTPaginatedResult<ARTPresenceMessage *> * _Nullable, ARTErrorInfo * _Nullable))callback error:(NSError **)errorPtr {
-    NSAssert(false, @"-[%@ %@] should always be overriden.", self.class, NSStringFromSelector(_cmd));
-    return false;
-}
-
 - (void)history:(void (^)(__GENERIC(ARTPaginatedResult, ARTPresenceMessage *) *, ARTErrorInfo *))callback {
-    [self history:[[ARTDataQuery alloc] init] callback:callback error:nil];
-}
-
-- (BOOL)history:(ARTDataQuery *)query callback:(void (^)(__GENERIC(ARTPaginatedResult, ARTPresenceMessage *) *, ARTErrorInfo *))callback error:(NSError **)errorPtr {
     NSAssert(false, @"-[%@ %@] should always be overriden.", self.class, NSStringFromSelector(_cmd));
-    return NO;
 }
 
 @end
diff --git a/Source/ARTRealtimeChannel+Private.h b/Source/ARTRealtimeChannel+Private.h
index 53876e306..28b2034fd 100644
--- a/Source/ARTRealtimeChannel+Private.h
+++ b/Source/ARTRealtimeChannel+Private.h
@@ -7,6 +7,7 @@
 //  Copyright (c) 2015 Ably. All rights reserved.
 //
 
+#import "ARTRestChannel.h"
 #import "ARTRealtimeChannel.h"
 #import "ARTEventEmitter.h"
 
@@ -18,6 +19,7 @@ ART_ASSUME_NONNULL_BEGIN
 @interface ARTRealtimeChannel ()
 
 @property (readonly, weak, nonatomic) ARTRealtime *realtime;
+@property (readonly, strong, nonatomic) ARTRestChannel *restChannel;
 @property (readwrite, strong, nonatomic) NSMutableArray *queuedMessages;
 @property (readwrite, strong, nonatomic, art_nullable) NSString *attachSerial;
 @property (readonly, getter=getClientId) NSString *clientId;
diff --git a/Source/ARTRealtimeChannel.h b/Source/ARTRealtimeChannel.h
index 22fd47c19..2b20f4446 100644
--- a/Source/ARTRealtimeChannel.h
+++ b/Source/ARTRealtimeChannel.h
@@ -17,7 +17,9 @@
 
 ART_ASSUME_NONNULL_BEGIN
 
-@interface ARTRealtimeChannel : ARTRestChannel
+@class ARTRealtimePresence;
+
+@interface ARTRealtimeChannel : ARTChannel
 
 @property (readwrite, assign, nonatomic) ARTRealtimeChannelState state;
 @property (readonly, strong, nonatomic, art_nullable) ARTErrorInfo *errorReason;
@@ -38,8 +40,7 @@ ART_ASSUME_NONNULL_BEGIN
 - (void)unsubscribe:(__GENERIC(ARTEventListener, ARTMessage *) *__art_nullable)listener;
 - (void)unsubscribe:(NSString *)name listener:(__GENERIC(ARTEventListener, ARTMessage *) *__art_nullable)listener;
 
-- (void)history:(void(^)(__GENERIC(ARTPaginatedResult, ARTMessage *) *__art_nullable result, ARTErrorInfo *__art_nullable error))callback;
-- (BOOL)history:(art_nullable ARTRealtimeHistoryQuery *)query callback:(void(^)(__GENERIC(ARTPaginatedResult, ARTMessage *) *__art_nullable result, ARTErrorInfo *__art_nullable error))callback error:(NSError *__art_nullable *__art_nullable)errorPtr;
+- (BOOL)history:(ARTRealtimeHistoryQuery *__art_nullable)query callback:(void(^)(__GENERIC(ARTPaginatedResult, ARTMessage *) *__art_nullable result, ARTErrorInfo *__art_nullable error))callback error:(NSError *__art_nullable *__art_nullable)errorPtr;
 
 ART_EMBED_INTERFACE_EVENT_EMITTER(ARTChannelEvent, ARTErrorInfo *)
 
diff --git a/Source/ARTRealtimeChannel.m b/Source/ARTRealtimeChannel.m
index e4e48baa8..8b565f65a 100644
--- a/Source/ARTRealtimeChannel.m
+++ b/Source/ARTRealtimeChannel.m
@@ -14,7 +14,7 @@
 #import "ARTMessage.h"
 #import "ARTBaseMessage+Private.h"
 #import "ARTAuth.h"
-#import "ARTRealtimePresence.h"
+#import "ARTRealtimePresence+Private.h"
 #import "ARTChannel.h"
 #import "ARTChannelOptions.h"
 #import "ARTProtocolMessage.h"
@@ -24,6 +24,7 @@
 #import "ARTNSArray+ARTFunctional.h"
 #import "ARTStatus.h"
 #import "ARTDefault.h"
+#import "ARTRest.h"
 #import "ARTClientOptions.h"
 
 @interface ARTRealtimeChannel () {
@@ -39,9 +40,10 @@ @interface ARTRealtimeChannel () {
 @implementation ARTRealtimeChannel
 
 - (instancetype)initWithRealtime:(ARTRealtime *)realtime andName:(NSString *)name withOptions:(ARTChannelOptions *)options {
-    self = [super initWithName:name withOptions:options andRest:realtime.rest];
+    self = [super initWithName:name andOptions:options andLogger:realtime.options.logHandler];
     if (self) {
         _realtime = realtime;
+        _restChannel = [_realtime.rest.channels get:self.name options:options];
         _state = ARTRealtimeChannelInitialized;
         _queuedMessages = [NSMutableArray array];
         _attachSerial = nil;
@@ -645,13 +647,13 @@ - (void)history:(void (^)(__GENERIC(ARTPaginatedResult, ARTMessage *) *, ARTErro
 - (BOOL)history:(ARTRealtimeHistoryQuery *)query callback:(void (^)(__GENERIC(ARTPaginatedResult, ARTMessage *) *, ARTErrorInfo *))callback error:(NSError **)errorPtr {
     query.realtimeChannel = self;
     @try {
-        return [super history:query callback:callback error:errorPtr];
+        return [_restChannel history:query callback:callback error:errorPtr];
     }
     @catch (NSError *error) {
         if (errorPtr) {
             *errorPtr = error;
         }
-        return false;
+        return NO;
     }
 }
 
diff --git a/Source/ARTRealtimePresence+Private.h b/Source/ARTRealtimePresence+Private.h
new file mode 100644
index 000000000..7296812aa
--- /dev/null
+++ b/Source/ARTRealtimePresence+Private.h
@@ -0,0 +1,20 @@
+//
+//  ARTRealtimePresence+Private.h
+//  ably
+//
+//  Created by Toni Cárdenas on 7/4/16.
+//  Copyright © 2016 Ably. All rights reserved.
+//
+
+#ifndef ARTRealtimePresence_Private_h
+#define ARTRealtimePresence_Private_h
+
+#import "ARTRealtimePresence.h"
+
+@interface ARTRealtimePresence ()
+
+- (instancetype)initWithChannel:(ARTRealtimeChannel *)channel;
+
+@end
+
+#endif /* ARTRealtimePresence_Private_h */
diff --git a/Source/ARTRealtimePresence.h b/Source/ARTRealtimePresence.h
index f51d4f64f..7d8d7c8da 100644
--- a/Source/ARTRealtimePresence.h
+++ b/Source/ARTRealtimePresence.h
@@ -10,8 +10,7 @@
 #import "ARTRestPresence.h"
 #import "ARTDataQuery.h"
 #import "ARTEventEmitter.h"
-
-@class ARTRealtimeChannel;
+#import "ARTRealtimeChannel.h"
 
 ART_ASSUME_NONNULL_BEGIN
 
@@ -21,12 +20,10 @@ ART_ASSUME_NONNULL_BEGIN
 
 @end
 
-@interface ARTRealtimePresence : ARTRestPresence
+@interface ARTRealtimePresence : ARTPresence
 
 @property (readonly, getter=getSyncComplete) BOOL syncComplete;
 
-- (instancetype)initWithChannel:(ARTRealtimeChannel *)channel;
-
 - (void)get:(void (^)(__GENERIC(NSArray, ARTPresenceMessage *) *__art_nullable result, ARTErrorInfo *__art_nullable error))callback;
 - (void)get:(ARTRealtimePresenceQuery *)query callback:(void (^)(__GENERIC(NSArray, ARTPresenceMessage *) *__art_nullable result, ARTErrorInfo *__art_nullable error))callback;
 
@@ -58,7 +55,7 @@ ART_ASSUME_NONNULL_BEGIN
 - (void)unsubscribe:(ARTPresenceAction)action listener:(__GENERIC(ARTEventListener, ARTPresenceMessage *) *)listener;
 
 - (void)history:(void(^)(__GENERIC(ARTPaginatedResult, ARTPresenceMessage *) *__art_nullable result, ARTErrorInfo *__art_nullable error))callback;
-- (BOOL)history:(art_nullable ARTRealtimeHistoryQuery *)query callback:(void(^)(__GENERIC(ARTPaginatedResult, ARTPresenceMessage *) *__art_nullable result, ARTErrorInfo *__art_nullable error))callback error:(NSError *__art_nullable *__art_nullable)errorPtr;
+- (BOOL)history:(ARTRealtimeHistoryQuery *__art_nullable)query callback:(void(^)(__GENERIC(ARTPaginatedResult, ARTPresenceMessage *) *__art_nullable result, ARTErrorInfo *__art_nullable error))callback error:(NSError *__art_nullable *__art_nullable)errorPtr;
 
 @end
 
diff --git a/Source/ARTRealtimePresence.m b/Source/ARTRealtimePresence.m
index 585eb60ec..826464938 100644
--- a/Source/ARTRealtimePresence.m
+++ b/Source/ARTRealtimePresence.m
@@ -6,9 +6,9 @@
 //  Copyright © 2015 Ably. All rights reserved.
 //
 
-#import "ARTRealtimePresence.h"
+#import "ARTRealtimePresence+Private.h"
 
-#import "ARTRealtime.h"
+#import "ARTRealtime+Private.h"
 #import "ARTRealtimeChannel+Private.h"
 #import "ARTPresenceMap.h"
 #import "ARTPresenceMessage.h"
@@ -32,38 +32,32 @@ - (instancetype)initWithLimit:(NSUInteger)limit clientId:(NSString *)clientId co
 
 #pragma mark - ARTRealtimePresence
 
-@interface ARTRealtimePresence ()
-
-@property (readonly, getter=getChannel) ARTRealtimeChannel *channel;
-
-@end
-
-@implementation ARTRealtimePresence
+@implementation ARTRealtimePresence {
+    __weak ARTRealtimeChannel *_channel;
+}
 
 - (instancetype)initWithChannel:(ARTRealtimeChannel *)channel {
-    self = [super initWithChannel:channel];
+    if (self = [super init]) {
+        _channel = channel;
+    }
     return self;
 }
 
-- (ARTRealtimeChannel *)getChannel {
-    return (ARTRealtimeChannel *)super.channel;
-}
-
 - (void)get:(void (^)(NSArray<ARTPresenceMessage *> *, ARTErrorInfo *))callback {
     [self get:[[ARTRealtimePresenceQuery alloc] init] callback:callback];
 }
 
 - (void)get:(ARTRealtimePresenceQuery *)query callback:(void (^)(NSArray<ARTPresenceMessage *> *, ARTErrorInfo *))callback {
-    [self.channel throwOnDisconnectedOrFailed];
-    [self.channel attach:^(ARTErrorInfo *error) {
+    [_channel throwOnDisconnectedOrFailed];
+    [_channel attach:^(ARTErrorInfo *error) {
         if (error) {
             callback(nil, error);
         } else if (query.waitForSync) {
-            [self.channel.presenceMap onceSyncEnds:^(NSArray<ARTPresenceMessage *> *members) {
+            [_channel.presenceMap onceSyncEnds:^(NSArray<ARTPresenceMessage *> *members) {
                 callback(members, nil);
             }];
         } else {
-            callback(self.channel.presenceMap.members.allValues, nil);
+            callback(_channel.presenceMap.members.allValues, nil);
         }
     }];
 }
@@ -73,9 +67,9 @@ - (void)history:(void (^)(__GENERIC(ARTPaginatedResult, ARTPresenceMessage *) *,
 }
 
 - (BOOL)history:(ARTRealtimeHistoryQuery *)query callback:(void (^)(__GENERIC(ARTPaginatedResult, ARTPresenceMessage *) *, ARTErrorInfo *))callback error:(NSError **)errorPtr {
-    query.realtimeChannel = self.channel;
+    query.realtimeChannel = _channel;
     @try {
-        return [super history:query callback:callback error:errorPtr];
+        return [_channel.restChannel.presence history:query callback:callback error:errorPtr];
     }
     @catch (NSError *error) {
         if (errorPtr) {
@@ -90,7 +84,7 @@ - (void)enter:(id)data {
 }
 
 - (void)enter:(id)data callback:(void (^)(ARTErrorInfo *))cb {
-    [self enterClient:self.channel.clientId data:data callback:cb];
+    [self enterClient:_channel.clientId data:data callback:cb];
 }
 
 - (void)enterClient:(NSString *)clientId data:(id)data {
@@ -107,8 +101,8 @@ - (void)enterClient:(NSString *)clientId data:(id)data callback:(void (^)(ARTErr
     msg.clientId = clientId;
     msg.data = data;
 
-    msg.connectionId = self.channel.realtime.connection.id;
-    [self.channel publishPresence:msg callback:cb];
+    msg.connectionId = _channel.realtime.connection.id;
+    [_channel publishPresence:msg callback:cb];
 }
 
 - (void)update:(id)data {
@@ -116,7 +110,7 @@ - (void)update:(id)data {
 }
 
 - (void)update:(id)data callback:(void (^)(ARTErrorInfo * _Nullable))cb {
-    [self updateClient:self.channel.clientId data:data callback:cb];
+    [self updateClient:_channel.clientId data:data callback:cb];
 }
 
 - (void)updateClient:(NSString *)clientId data:(id)data {
@@ -132,9 +126,9 @@ - (void)updateClient:(NSString *)clientId data:(id)data callback:(void (^)(ARTEr
     msg.action = ARTPresenceUpdate;
     msg.clientId = clientId;
     msg.data = data;
-    msg.connectionId = self.channel.realtime.connection.id;
+    msg.connectionId = _channel.realtime.connection.id;
 
-    [self.channel publishPresence:msg callback:cb];
+    [_channel publishPresence:msg callback:cb];
 }
 
 - (void)leave:(id)data {
@@ -142,7 +136,7 @@ - (void)leave:(id)data {
 }
 
 - (void)leave:(id)data callback:(void (^)(ARTErrorInfo * _Nullable))cb {
-    [self leaveClient:self.channel.clientId data:data callback:cb];
+    [self leaveClient:_channel.clientId data:data callback:cb];
 }
 
 - (void)leaveClient:(NSString *)clientId data:(id)data {
@@ -154,8 +148,8 @@ - (void)leaveClient:(NSString *)clientId data:(id)data callback:(void (^)(ARTErr
         if (cb) cb([ARTErrorInfo createWithCode:ARTStateNoClientId message:@"attempted to publish presence message without clientId"]);
         return;
     }
-    if ([clientId isEqualToString:self.channel.clientId]) {
-        if(self.channel.lastPresenceAction != ARTPresenceEnter && self.channel.lastPresenceAction != ARTPresenceUpdate) {
+    if ([clientId isEqualToString:_channel.clientId]) {
+        if(_channel.lastPresenceAction != ARTPresenceEnter && _channel.lastPresenceAction != ARTPresenceUpdate) {
             [NSException raise:@"Cannot leave a channel before you've entered it" format:@""];
         }
     }
@@ -163,12 +157,12 @@ - (void)leaveClient:(NSString *)clientId data:(id)data callback:(void (^)(ARTErr
     msg.action = ARTPresenceLeave;
     msg.data = data;
     msg.clientId = clientId;
-    msg.connectionId = self.channel.realtime.connection.id;
-    [self.channel publishPresence:msg callback:cb];
+    msg.connectionId = _channel.realtime.connection.id;
+    [_channel publishPresence:msg callback:cb];
 }
 
 - (BOOL)getSyncComplete {
-    return self.channel.presenceMap.syncComplete;
+    return _channel.presenceMap.syncComplete;
 }
 
 - (ARTEventListener<ARTPresenceMessage *> *)subscribe:(void (^)(ARTPresenceMessage * _Nonnull))callback {
@@ -176,12 +170,12 @@ - (BOOL)getSyncComplete {
 }
 
 - (ARTEventListener<ARTPresenceMessage *> *)subscribeWithAttachCallback:(void (^)(ARTErrorInfo * _Nullable))onAttach callback:(void (^)(ARTPresenceMessage * _Nonnull))cb {
-    if (self.channel.state == ARTRealtimeChannelFailed) {
+    if (_channel.state == ARTRealtimeChannelFailed) {
         if (onAttach) onAttach([ARTErrorInfo createWithCode:0 message:@"attempted to subscribe while channel is in Failed state."]);
         return nil;
     }
-    [self.channel attach:onAttach];
-    return [self.channel.presenceEventEmitter on:cb];
+    [_channel attach:onAttach];
+    return [_channel.presenceEventEmitter on:cb];
 }
 
 - (ARTEventListener<ARTPresenceMessage *> *)subscribe:(ARTPresenceAction)action callback:(void (^)(ARTPresenceMessage * _Nonnull))cb {
@@ -189,24 +183,24 @@ - (BOOL)getSyncComplete {
 }
 
 - (ARTEventListener<ARTPresenceMessage *> *)subscribe:(ARTPresenceAction)action onAttach:(void (^)(ARTErrorInfo * _Nullable))onAttach callback:(void (^)(ARTPresenceMessage * _Nonnull))cb {
-    if (self.channel.state == ARTRealtimeChannelFailed) {
+    if (_channel.state == ARTRealtimeChannelFailed) {
         if (onAttach) onAttach([ARTErrorInfo createWithCode:0 message:@"attempted to subscribe while channel is in Failed state."]);
         return nil;
     }
-    [self.channel attach:onAttach];
-    return [self.channel.presenceEventEmitter on:[NSNumber numberWithUnsignedInteger:action] call:cb];
+    [_channel attach:onAttach];
+    return [_channel.presenceEventEmitter on:[NSNumber numberWithUnsignedInteger:action] call:cb];
 }
 
 - (void)unsubscribe {
-    [self.channel.presenceEventEmitter off];
+    [_channel.presenceEventEmitter off];
 }
 
 - (void)unsubscribe:(ARTEventListener<ARTPresenceMessage *> *)listener {
-    [self.channel.presenceEventEmitter off:listener];
+    [_channel.presenceEventEmitter off:listener];
 }
 
 - (void)unsubscribe:(ARTPresenceAction)action listener:(ARTEventListener<ARTPresenceMessage *> *)listener {
-    [self.channel.presenceEventEmitter off:[NSNumber numberWithUnsignedInteger:action] listener:listener];
+    [_channel.presenceEventEmitter off:[NSNumber numberWithUnsignedInteger:action] listener:listener];
 }
 
 @end
diff --git a/Source/ARTRestChannel+Private.h b/Source/ARTRestChannel+Private.h
index 1abefc69f..8bd844562 100644
--- a/Source/ARTRestChannel+Private.h
+++ b/Source/ARTRestChannel+Private.h
@@ -11,6 +11,8 @@
 
 @interface ARTRestChannel ()
 
+- (instancetype)initWithName:(NSString *)name withOptions:(ARTChannelOptions *)options andRest:(ARTRest *)rest;
+
 @property (nonatomic, weak) ARTRest *rest;
 
 @end
diff --git a/Source/ARTRestChannel.h b/Source/ARTRestChannel.h
index 8767da652..713a45a4f 100644
--- a/Source/ARTRestChannel.h
+++ b/Source/ARTRestChannel.h
@@ -19,7 +19,7 @@ ART_ASSUME_NONNULL_BEGIN
 
 @property (readonly, getter=getPresence) ARTRestPresence *presence;
 
-- (instancetype)initWithName:(NSString *)name withOptions:(ARTChannelOptions *)options andRest:(ARTRest *)rest;
+- (BOOL)history:(art_nullable ARTDataQuery *)query callback:(void(^)(__GENERIC(ARTPaginatedResult, ARTMessage *) *__art_nullable result, ARTErrorInfo *__art_nullable error))callback error:(NSError *__art_nullable *__art_nullable)errorPtr;
 
 @end
 
diff --git a/Source/ARTRestChannel.m b/Source/ARTRestChannel.m
index 50cd53499..bea7717f4 100644
--- a/Source/ARTRestChannel.m
+++ b/Source/ARTRestChannel.m
@@ -9,7 +9,7 @@
 #import "ARTRestChannel+Private.h"
 
 #import "ARTRest+Private.h"
-#import "ARTRestPresence.h"
+#import "ARTRestPresence+Private.h"
 #import "ARTChannel+Private.h"
 #import "ARTChannelOptions.h"
 #import "ARTMessage.h"
@@ -52,6 +52,10 @@ - (ARTRestPresence *)getPresence {
     return _restPresence;
 }
 
+- (void)history:(void (^)(__GENERIC(ARTPaginatedResult, ARTMessage *) *, ARTErrorInfo *))callback {
+    [self history:[[ARTDataQuery alloc] init] callback:callback error:nil];
+}
+
 - (BOOL)history:(ARTDataQuery *)query callback:(void(^)(__GENERIC(ARTPaginatedResult, ARTMessage *) *result, ARTErrorInfo *error))callback error:(NSError **)errorPtr {
     if (query.limit > 1000) {
         if (errorPtr) {
diff --git a/Source/ARTRestChannels.m b/Source/ARTRestChannels.m
index c11491a4f..eb5103792 100644
--- a/Source/ARTRestChannels.m
+++ b/Source/ARTRestChannels.m
@@ -9,6 +9,7 @@
 #import <Foundation/Foundation.h>
 #import "ARTRestChannels.h"
 #import "ARTChannels+Private.h"
+#import "ARTRestChannel+Private.h"
 
 @interface ARTRestChannels ()
 
diff --git a/Source/ARTRestPresence+Private.h b/Source/ARTRestPresence+Private.h
new file mode 100644
index 000000000..ac1a8764e
--- /dev/null
+++ b/Source/ARTRestPresence+Private.h
@@ -0,0 +1,24 @@
+//
+//  ARTRestPresence+Private.h
+//  ably
+//
+//  Created by Toni Cárdenas on 7/4/16.
+//  Copyright © 2016 Ably. All rights reserved.
+//
+
+#ifndef ARTRestPresence_Private_h
+#define ARTRestPresence_Private_h
+
+#import "ARTRestPresence.h"
+
+ART_ASSUME_NONNULL_BEGIN
+
+@interface ARTRestPresence ()
+
+- (instancetype)initWithChannel:(ARTRestChannel *)channel;
+
+@end
+
+ART_ASSUME_NONNULL_END
+
+#endif /* ARTRestPresence_Private_h */
diff --git a/Source/ARTRestPresence.h b/Source/ARTRestPresence.h
index db87a9468..d7c9150a2 100644
--- a/Source/ARTRestPresence.h
+++ b/Source/ARTRestPresence.h
@@ -8,14 +8,31 @@
 
 #import <Foundation/Foundation.h>
 #import "ARTPresence.h"
+#import "ARTDataQuery.h"
 
 @class ARTRestChannel;
 
 ART_ASSUME_NONNULL_BEGIN
 
+@interface ARTPresenceQuery : NSObject
+
+@property (nonatomic, readwrite) NSUInteger limit;
+@property (nonatomic, strong, readwrite) NSString *clientId;
+@property (nonatomic, strong, readwrite) NSString *connectionId;
+
+- (instancetype)init;
+- (instancetype)initWithClientId:(NSString *__art_nullable)clientId connectionId:(NSString *__art_nullable)connectionId;
+- (instancetype)initWithLimit:(NSUInteger)limit clientId:(NSString *__art_nullable)clientId connectionId:(NSString *__art_nullable)connectionId;
+
+@end
+
 @interface ARTRestPresence : ARTPresence
 
-- (instancetype)initWithChannel:(ARTRestChannel *)channel;
+- (void)get:(void (^)(__GENERIC(ARTPaginatedResult, ARTPresenceMessage *) *__art_nullable result, ARTErrorInfo *__art_nullable error))callback;
+- (BOOL)get:(void (^)(__GENERIC(ARTPaginatedResult, ARTPresenceMessage *) *__art_nullable result, ARTErrorInfo *__art_nullable error))callback error:(NSError *__art_nullable *__art_nullable)errorPtr;
+- (BOOL)get:(ARTPresenceQuery *)query callback:(void (^)(__GENERIC(ARTPaginatedResult, ARTPresenceMessage *) *__art_nullable result, ARTErrorInfo *__art_nullable error))callback error:(NSError *__art_nullable *__art_nullable)errorPtr;
+
+- (BOOL)history:(art_nullable ARTDataQuery *)query callback:(void(^)(__GENERIC(ARTPaginatedResult, ARTPresenceMessage *) *__art_nullable result, ARTErrorInfo *__art_nullable error))callback error:(NSError *__art_nullable *__art_nullable)errorPtr;
 
 @end
 
diff --git a/Source/ARTRestPresence.m b/Source/ARTRestPresence.m
index b501af484..5671dc01f 100644
--- a/Source/ARTRestPresence.m
+++ b/Source/ARTRestPresence.m
@@ -6,7 +6,7 @@
 //  Copyright © 2015 Ably. All rights reserved.
 //
 
-#import "ARTRestPresence.h"
+#import "ARTRestPresence+Private.h"
 
 #import "ARTPresence+Private.h"
 #import "ARTRest+Private.h"
@@ -18,14 +18,63 @@
 #import "ARTChannel+Private.h"
 #import "ARTBaseMessage+Private.h"
 
-@implementation ARTRestPresence
+#import "ARTChannel.h"
+#import "ARTDataQuery.h"
+
+@implementation ARTPresenceQuery
+
+- (instancetype)init {
+    return [self initWithClientId:nil connectionId:nil];
+}
+
+- (instancetype)initWithClientId:(NSString *)clientId connectionId:(NSString *)connectionId {
+    return [self initWithLimit:100 clientId:clientId connectionId:connectionId];
+}
+
+- (instancetype)initWithLimit:(NSUInteger)limit clientId:(NSString *)clientId connectionId:(NSString *)connectionId {
+    self = [super init];
+    if (self) {
+        _limit = limit;
+        _clientId = clientId;
+        _connectionId = connectionId;
+    }
+    return self;
+}
+
+- (NSMutableArray *)asQueryItems {
+    NSMutableArray *items = [NSMutableArray array];
+
+    if (self.clientId) {
+        [items addObject:[NSURLQueryItem queryItemWithName:@"clientId" value:self.clientId]];
+    }
+    if (self.connectionId) {
+        [items addObject:[NSURLQueryItem queryItemWithName:@"connectionId" value:self.connectionId]];
+    }
+
+    [items addObject:[NSURLQueryItem queryItemWithName:@"limit" value:[NSString stringWithFormat:@"%lu", (unsigned long)self.limit]]];
+
+    return items;
+}
+
+@end
+
+@implementation ARTRestPresence {
+    __weak ARTRestChannel *_channel;
+}
 
 - (instancetype)initWithChannel:(ARTRestChannel *)channel {
-    return [super initWithChannel:channel];
+    if (self = [super init]) {
+        _channel = channel;
+    }
+    return self;
+}
+
+- (void)get:(void (^)(__GENERIC(ARTPaginatedResult, ARTPresenceMessage *) *result, ARTErrorInfo *error))callback {
+    [self get:[[ARTPresenceQuery alloc] init] callback:callback error:nil];
 }
 
-- (ARTRestChannel *)channel {
-    return (ARTRestChannel *)super.channel;
+- (BOOL)get:(void (^)(__GENERIC(ARTPaginatedResult, ARTPresenceMessage *) *result, ARTErrorInfo *error))callback error:(NSError **)errorPtr {
+    return [self get:[[ARTPresenceQuery alloc] init] callback:callback error:errorPtr];
 }
 
 - (BOOL)get:(ARTPresenceQuery *)query callback:(void (^)(ARTPaginatedResult<ARTPresenceMessage *> *, ARTErrorInfo *))callback error:(NSError **)errorPtr {
@@ -38,26 +87,30 @@ - (BOOL)get:(ARTPresenceQuery *)query callback:(void (^)(ARTPaginatedResult<ARTP
         return NO;
     }
 
-    NSURLComponents *requestUrl = [NSURLComponents componentsWithString:[[self channel].basePath stringByAppendingPathComponent:@"presence"]];
+    NSURLComponents *requestUrl = [NSURLComponents componentsWithString:[_channel.basePath stringByAppendingPathComponent:@"presence"]];
     requestUrl.queryItems = [query asQueryItems];
     NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:requestUrl.URL];
 
     ARTPaginatedResultResponseProcessor responseProcessor = ^(NSHTTPURLResponse *response, NSData *data) {
-        id<ARTEncoder> encoder = [[self channel].rest.encoders objectForKey:response.MIMEType];
+        id<ARTEncoder> encoder = [_channel.rest.encoders objectForKey:response.MIMEType];
         return [[encoder decodePresenceMessages:data] artMap:^(ARTPresenceMessage *message) {
             // FIXME: This should be refactored to be done by ART{Json,...}Encoder.
             // The ART{Json,...}Encoder should take a ARTDataEncoder and use it every
             // time it is enc/decoding a message. This also applies for REST and Realtime
             // ARTMessages.
-            message = [message decodeWithEncoder:self.channel.dataEncoder error:nil];
+            message = [message decodeWithEncoder:_channel.dataEncoder error:nil];
             return message;
         }];
     };
 
-    [ARTPaginatedResult executePaginated:[self channel].rest withRequest:request andResponseProcessor:responseProcessor callback:callback];
+    [ARTPaginatedResult executePaginated:_channel.rest withRequest:request andResponseProcessor:responseProcessor callback:callback];
     return YES;
 }
 
+- (void)history:(void (^)(__GENERIC(ARTPaginatedResult, ARTPresenceMessage *) *, ARTErrorInfo *))callback {
+    [self history:[[ARTDataQuery alloc] init] callback:callback error:nil];
+}
+
 - (BOOL)history:(ARTDataQuery *)query callback:(void(^)(__GENERIC(ARTPaginatedResult, ARTPresenceMessage *) *result, ARTErrorInfo *error))callback error:(NSError **)errorPtr {
     if (query.limit > 1000) {
         if (errorPtr) {
@@ -76,16 +129,16 @@ - (BOOL)history:(ARTDataQuery *)query callback:(void(^)(__GENERIC(ARTPaginatedRe
         return NO;
     }
 
-    NSURLComponents *requestUrl = [NSURLComponents componentsWithString:[[self channel].basePath stringByAppendingPathComponent:@"presence/history"]];
+    NSURLComponents *requestUrl = [NSURLComponents componentsWithString:[_channel.basePath stringByAppendingPathComponent:@"presence/history"]];
     requestUrl.queryItems = [query asQueryItems];
     NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:requestUrl.URL];
 
     ARTPaginatedResultResponseProcessor responseProcessor = ^(NSHTTPURLResponse *response, NSData *data) {
-        id<ARTEncoder> encoder = [[self channel].rest.encoders objectForKey:response.MIMEType];
+        id<ARTEncoder> encoder = [_channel.rest.encoders objectForKey:response.MIMEType];
         return [encoder decodePresenceMessages:data];
     };
 
-    [ARTPaginatedResult executePaginated:[self channel].rest withRequest:request andResponseProcessor:responseProcessor callback:callback];
+    [ARTPaginatedResult executePaginated:_channel.rest withRequest:request andResponseProcessor:responseProcessor callback:callback];
     return YES;
 }
 
diff --git a/Spec/RealtimeClientChannel.swift b/Spec/RealtimeClientChannel.swift
index 689ecef4d..36661f0b6 100644
--- a/Spec/RealtimeClientChannel.swift
+++ b/Spec/RealtimeClientChannel.swift
@@ -828,7 +828,8 @@ class RealtimeClientChannel: QuickSpec {
                                 for index in 1...TotalMessages.expected {
                                     channelToSucceed.publish(nil, data: "message\(index)") { errorInfo in
                                         if errorInfo == nil {
-                                            expect(index).to(equal(++TotalMessages.succeeded), description: "Callback was invoked with an invalid sequence")
+                                            TotalMessages.succeeded += 1
+                                            expect(index).to(equal(TotalMessages.succeeded), description: "Callback was invoked with an invalid sequence")
                                         }
                                     }
                                 }
@@ -842,7 +843,8 @@ class RealtimeClientChannel: QuickSpec {
                                 for index in 1...TotalMessages.expected {
                                     channelToFail.publish(nil, data: "message\(index)") { errorInfo in
                                         if errorInfo != nil {
-                                            expect(index).to(equal(++TotalMessages.failed), description: "Callback was invoked with an invalid sequence")
+                                            TotalMessages.failed += 1
+                                            expect(index).to(equal(TotalMessages.failed), description: "Callback was invoked with an invalid sequence")
                                         }
                                     }
                                 }
diff --git a/Spec/RealtimeClientConnection.swift b/Spec/RealtimeClientConnection.swift
index f12dada46..06c028337 100644
--- a/Spec/RealtimeClientConnection.swift
+++ b/Spec/RealtimeClientConnection.swift
@@ -12,7 +12,7 @@ import Nimble
 func countChannels(channels: ARTRealtimeChannels) -> Int {
     var i = 0
     for _ in channels {
-        i++
+        i += 1
     }
     return i
 }
@@ -393,7 +393,7 @@ class RealtimeClientConnection: QuickSpec {
 
                     channel.on { errorInfo in
                         if channel.state == .Attached {
-                            TotalReach.shared++
+                            TotalReach.shared += 1
                         }
                     }
 
@@ -409,7 +409,7 @@ class RealtimeClientConnection: QuickSpec {
 
                     channel.subscribe { message in
                         expect(message.data as? String).to(equal("message_string"))
-                        TotalReach.shared++
+                        TotalReach.shared += 1
                     }
 
                     channel.publish(nil, data: "message_string", callback: nil)
@@ -648,7 +648,7 @@ class RealtimeClientConnection: QuickSpec {
                         for index in 1...TotalMessages.expected {
                             channel.publish(nil, data: "message\(index)") { errorInfo in
                                 if errorInfo == nil {
-                                    TotalMessages.succeeded++
+                                    TotalMessages.succeeded += 1
                                 }
                             }
                         }
diff --git a/Spec/RestClientChannel.swift b/Spec/RestClientChannel.swift
index f418bf26b..6e52657b4 100644
--- a/Spec/RestClientChannel.swift
+++ b/Spec/RestClientChannel.swift
@@ -168,7 +168,8 @@ class RestClientChannel: QuickSpec {
                             expect(client.auth.method).to(equal(ARTAuthMethod.Basic))
                             channel.history { page, error in
                                 expect(error).to(beNil())
-                                expect(page!.items[0].clientId).to(equal("tester"))
+                                let item = page!.items[0] as! ARTMessage
+                                expect(item.clientId).to(equal("tester"))
                                 done()
                             }
                         }
@@ -197,7 +198,8 @@ class RestClientChannel: QuickSpec {
                                 expect(error).to(beNil())
                                 channel.history { page, error in
                                     expect(error).to(beNil())
-                                    expect(page!.items[0].clientId).to(equal("john"))
+                                    let item = page!.items[0] as! ARTMessage
+                                    expect(item.clientId).to(equal("john"))
                                     done()
                                 }
                             }
@@ -219,7 +221,8 @@ class RestClientChannel: QuickSpec {
                             expect(error).to(beNil())
                             channel.history { page, error in
                                 expect(error).to(beNil())
-                                expect(page!.items[0].clientId).to(equal("john"))
+                                let item = page!.items[0] as! ARTMessage
+                                expect(item.clientId).to(equal("john"))
                                 done()
                             }
                         }
@@ -459,7 +462,7 @@ class RestClientChannel: QuickSpec {
                         expect(result.hasNext).to(beFalse())
 
                         for (index, item) in (result.items.reverse().enumerate()) {
-                            totalReceived++
+                            totalReceived += 1
 
                             switch (item as? ARTMessage)?.data {
                             case let value as NSDictionary:
diff --git a/Spec/RestClientPresence.swift b/Spec/RestClientPresence.swift
index 29b6831fb..6a4f89721 100644
--- a/Spec/RestClientPresence.swift
+++ b/Spec/RestClientPresence.swift
@@ -327,6 +327,52 @@ class RestClientPresence: QuickSpec {
                     }
                 }
 
+                // RSP3a3
+                it("connectionId should filter members by the provided connectionId") {
+                    let options = AblyTests.commonAppSetup()
+                    let client = ARTRest(options: options)
+                    let channel = client.channels.get("test")
+
+                    var disposable = [ARTRealtime]()
+                    defer {
+                        for clientItem in disposable {
+                            clientItem.close()
+                        }
+                    }
+
+                    waitUntil(timeout: testTimeout) { done in
+                        // One connection
+                        disposable += AblyTests.addMembersSequentiallyToChannel("test", members: 6, options: options) {
+                            done()
+                        }
+                    }
+
+                    waitUntil(timeout: testTimeout) { done in
+                        // Another connection
+                        disposable += AblyTests.addMembersSequentiallyToChannel("test", members: 3, startFrom: 7, options: options) {
+                            done()
+                        }
+                    }
+
+                    let query = ARTRealtimePresenceQuery()
+                    // Return all members from last connection (connectionId from the last connection)
+                    query.connectionId = disposable.last!.connection.id!
+
+                    waitUntil(timeout: testTimeout) { done in
+                        try! channel.presence.get(query) { membersPage, error in
+                            expect(error).to(beNil())
+                            expect(membersPage!.items).to(haveCount(3))
+                            expect(membersPage!.hasNext).to(beFalse())
+                            expect(membersPage!.isLast).to(beTrue())
+                            expect(membersPage!.items).to(allPass({ member in
+                                let member = member as! ARTPresenceMessage?
+                                return NSRegularExpression.match(member!.clientId, pattern: "^user(7|8|9)")
+                            }))
+                            done()
+                        }
+                    }
+                }
+
             }
 
             // RSP4
diff --git a/Tests/ARTRestChannelHistoryTest.m b/Tests/ARTRestChannelHistoryTest.m
index 24d935a1b..a10d58aba 100644
--- a/Tests/ARTRestChannelHistoryTest.m
+++ b/Tests/ARTRestChannelHistoryTest.m
@@ -118,7 +118,7 @@ - (void)testTimeForwards {
     __weak XCTestExpectation *firstExpectation = [self expectationWithDescription:@"getTime"];
     [ARTTestUtil testRest:^(ARTRest *rest) {
         _rest = rest;
-        ARTChannel *channel = [rest.channels get:@"test_history_time_forwards"];
+        ARTRestChannel *channel = [rest.channels get:@"test_history_time_forwards"];
 
         int firstBatchTotal = 2;
         int secondBatchTotal = 5;
@@ -177,7 +177,7 @@ - (void)testHistoryForwardPagination {
     __weak XCTestExpectation *firstExpectation = [self expectationWithDescription:@"send_second_batch"];
     [ARTTestUtil testRest:^(ARTRest *rest) {
         _rest = rest;
-        ARTChannel *channel = [rest.channels get:@"testHistoryForwardPagination"];
+        ARTRestChannel *channel = [rest.channels get:@"testHistoryForwardPagination"];
         
         [ARTTestUtil publishRestMessages:@"testString" count:5 channel:channel completion:^{
             ARTDataQuery *query = [[ARTDataQuery alloc] init];
@@ -241,7 +241,7 @@ - (void)testHistoryBackwardPagination {
     __weak XCTestExpectation *firstExpectation = [self expectationWithDescription:@"send_second_batch"];
     [ARTTestUtil testRest:^(ARTRest *rest) {
         _rest = rest;
-        ARTChannel *channel = [rest.channels get:@"testHistoryBackwardPagination"];
+        ARTRestChannel *channel = [rest.channels get:@"testHistoryBackwardPagination"];
 
         [ARTTestUtil publishRestMessages:@"testString" count:5 channel:channel completion:^{
             ARTDataQuery *query = [[ARTDataQuery alloc] init];
@@ -305,7 +305,7 @@ - (void)testHistoryBackwardDefault {
     __weak XCTestExpectation *firstExpectation = [self expectationWithDescription:@"send_second_batch"];
     [ARTTestUtil testRest:^(ARTRest *rest) {
         _rest = rest;
-        ARTChannel *channel = [rest.channels get:@"testHistoryBackwardDefault"];
+        ARTRestChannel *channel = [rest.channels get:@"testHistoryBackwardDefault"];
 
         [ARTTestUtil publishRestMessages:@"testString" count:5 channel:channel completion:^{
             ARTDataQuery *query = [[ARTDataQuery alloc] init];
@@ -342,10 +342,10 @@ - (void)testHistoryTwoClients {
         ARTRest *rest2 = [[ARTRest alloc] initWithOptions:options];
         _rest2 = rest2;
 
-        ARTChannel *channelOne = [rest.channels get:channelName];
+        ARTRestChannel *channelOne = [rest.channels get:channelName];
 
         [ARTTestUtil publishRestMessages:@"testString" count:5 channel:channelOne completion:^{
-            ARTChannel *channelTwo = [rest2.channels get:channelName];
+            ARTRestChannel *channelTwo = [rest2.channels get:channelName];
 
             ARTDataQuery *query = [[ARTDataQuery alloc] init];
             query.limit = 2;
@@ -370,7 +370,7 @@ - (void)testHistoryLimit {
     __weak XCTestExpectation *exp = [self expectationWithDescription:@"testLimit"];
     [ARTTestUtil testRest:^(ARTRest *rest) {
         _rest = rest;
-        ARTChannel *channelOne = [rest.channels get:@"name"];
+        ARTRestChannel *channelOne = [rest.channels get:@"name"];
 
         ARTDataQuery *query = [[ARTDataQuery alloc] init];
         query.limit = 1001;
@@ -389,7 +389,7 @@ - (void)testHistoryLimitIgnoringError {
     __weak XCTestExpectation *exp = [self expectationWithDescription:@"testLimit"];
     [ARTTestUtil testRest:^(ARTRest *rest) {
         _rest = rest;
-        ARTChannel *channelOne = [rest.channels get:@"name"];
+        ARTRestChannel *channelOne = [rest.channels get:@"name"];
 
         ARTDataQuery *query = [[ARTDataQuery alloc] init];
         query.limit = 1001;
diff --git a/Tests/ARTRestChannelPublishTest.m b/Tests/ARTRestChannelPublishTest.m
index d277fe635..318dbdc18 100644
--- a/Tests/ARTRestChannelPublishTest.m
+++ b/Tests/ARTRestChannelPublishTest.m
@@ -38,7 +38,7 @@ - (void)testTypesByText {
     NSString *message2 = @"message2";
     [ARTTestUtil testRest:^(ARTRest *rest) {
         _rest = rest;
-        ARTChannel *channel = [rest.channels get:@"testTypesByText"];
+        ARTRestChannel *channel = [rest.channels get:@"testTypesByText"];
         [channel publish:nil data:message1 callback:^(ARTErrorInfo *error) {
             XCTAssert(!error);
             [channel publish:nil data:message2 callback:^(ARTErrorInfo *error) {