Browse files

First commit

  • Loading branch information...
1 parent c514abd commit 1d435db4c8d38c2b741caa62d8fb891c39168353 @stuartkhall committed Mar 6, 2012
View
20 .gitignore
@@ -0,0 +1,20 @@
+.DS_Store
+build
+Documentation/html
+Documentation/keys
+
+*.pbxuser
+*.mode1v3
+*.mode2v3
+!default.pbxuser
+!default.mode1v3
+!default.mode2v3
+
+*.perspective
+*.perspectivev3
+
+*.swp
+*~.nib
+*~.xib
+*.xcodeproj/xcuserdata/*
+*.xcodeproj/project.xcworkspace/xcuserdata/*
View
3 .gitmodules
@@ -0,0 +1,3 @@
+[submodule "TwitterStreams/Dependencies/JSONKit"]
+ path = TwitterStreams/Dependencies/JSONKit
+ url = git://github.com/johnezang/JSONKit.git
View
0 TwitterStreams/AppDelegate.h → ExampleApp/AppDelegate.h
File renamed without changes.
View
0 TwitterStreams/AppDelegate.m → ExampleApp/AppDelegate.m
File renamed without changes.
View
0 TwitterStreams/TwitterStreams-Info.plist → ExampleApp/TwitterStreams-Info.plist
File renamed without changes.
View
0 TwitterStreams/TwitterStreams-Prefix.pch → ExampleApp/TwitterStreams-Prefix.pch
File renamed without changes.
View
4 TwitterStreams/ViewController.h → ExampleApp/ViewController.h
@@ -8,6 +8,8 @@
#import <UIKit/UIKit.h>
-@interface ViewController : UIViewController
+#import "TSUserStream.h"
+
+@interface ViewController : UIViewController<UIActionSheetDelegate, TSStreamDelegate>
@end
View
175 ExampleApp/ViewController.m
@@ -0,0 +1,175 @@
+//
+// ViewController.m
+// TwitterStreams
+//
+// Created by Stuart Hall on 6/03/12.
+// Copyright (c) 2012 Filter Squad. All rights reserved.
+//
+
+#import "ViewController.h"
+
+#import "TSUserStream.h"
+#import "TSFilterStream.h"
+
+#import <Accounts/Accounts.h>
+#import <Twitter/Twitter.h>
+
+@interface ViewController ()
+
+@property (nonatomic, retain) ACAccountStore* accountStore;
+@property (nonatomic, retain) NSArray* accounts;
+@property (nonatomic, retain) ACAccount* account;
+
+@property (nonatomic, retain) TSStream* stream;
+
+@end
+
+@implementation ViewController
+
+@synthesize accountStore=_accountStore;
+@synthesize accounts=_accounts;
+@synthesize account=_account;
+@synthesize stream=_stream;
+
+- (void)dealloc {
+ self.accountStore = nil;
+ self.accounts = nil;
+ self.account = nil;
+ self.stream = nil;
+
+ [super dealloc];
+}
+
+- (void)viewDidLoad
+{
+ [super viewDidLoad];
+
+ // Get access to their accounts
+ self.accountStore = [[[ACAccountStore alloc] init] autorelease];
+ ACAccountType *accountTypeTwitter = [self.accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];
+ [self.accountStore requestAccessToAccountsWithType:accountTypeTwitter
+ withCompletionHandler:^(BOOL granted, NSError *error) {
+ if (granted && !error) {
+ dispatch_sync(dispatch_get_main_queue(), ^{
+ self.accounts = [self.accountStore accountsWithAccountType:accountTypeTwitter];
+ if (self.accounts.count == 0) {
+ [[[[UIAlertView alloc] initWithTitle:nil
+ message:@"Please add a Twitter account in the Settings app"
+ delegate:nil
+ cancelButtonTitle:@"OK"
+ otherButtonTitles:nil] autorelease] show];
+ }
+ else {
+ // Let them select the account they want to use
+ UIActionSheet* sheet = [[[UIActionSheet alloc] initWithTitle:@"Select your Twitter account:"
+ delegate:self
+ cancelButtonTitle:nil
+ destructiveButtonTitle:nil
+ otherButtonTitles:nil] autorelease];
+
+ for (ACAccount* account in self.accounts) {
+ [sheet addButtonWithTitle:account.accountDescription];
+ }
+
+ sheet.tag = 0;
+
+ [sheet showInView:self.view];
+ }
+ });
+ }
+ else {
+ dispatch_sync(dispatch_get_main_queue(), ^{
+ NSString* message = [NSString stringWithFormat:@"Error getting access to accounts : %@", [error localizedDescription]];
+ [[[[UIAlertView alloc] initWithTitle:nil
+ message:message
+ delegate:nil
+ cancelButtonTitle:@"OK"
+ otherButtonTitles:nil] autorelease] show];
+ });
+ }
+ }];
+}
+
+- (void)viewDidUnload
+{
+ [super viewDidUnload];
+ // Release any retained subviews of the main view.
+}
+
+- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
+{
+ return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
+}
+
+#pragma mark - UIActionSheetDelegate
+
+- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
+ switch (actionSheet.tag) {
+ case 0: {
+ if (buttonIndex < self.accounts.count) {
+ self.account = [self.accounts objectAtIndex:buttonIndex];
+
+ // Stream options
+ UIActionSheet* sheet = [[[UIActionSheet alloc] initWithTitle:@"Select stream type:"
+ delegate:self
+ cancelButtonTitle:nil
+ destructiveButtonTitle:nil
+ otherButtonTitles:@"User stream", @"Filter stream", nil] autorelease];
+ sheet.tag = 1;
+ [sheet showInView:self.view];
+ }
+ }
+ break;
+
+ case 1: {
+ self.stream = nil;
+
+ // Create a stream of the selected types
+ switch (buttonIndex) {
+ case 0: {
+ self.stream = [[[TSUserStream alloc] initWithAccount:self.account
+ andDelegate:self
+ andAllReplies:YES
+ andAllFollowings:YES] autorelease];
+ }
+ break;
+
+ case 1: {
+ self.stream = [[[TSFilterStream alloc] initWithAccount:self.account
+ andDelegate:self
+ andKeywords:[NSArray arrayWithObjects:@"stuartkhall", @"discovr", nil]] autorelease];
+
+ }
+ break;
+ }
+
+ if (self.stream)
+ [self.stream start];
+
+ }
+ break;
+ }
+}
+
+#pragma mark - TSStreamDelegate
+
+- (void)streamDidReceiveMessage:(TSStream*)stream json:(id)json {
+ NSLog(@"%@", json);
+}
+
+- (void)streamDidReceiveInvalidJson:(TSStream*)stream message:(NSString*)message {
+ NSLog(@"--\r\nInvalid JSON!!\r\n--");
+}
+
+- (void)streamDidTimeout:(TSStream*)stream {
+ NSLog(@"--\r\nStream timeout!!\r\n--");
+}
+
+- (void)streamDidFailConnection:(TSStream *)stream {
+ NSLog(@"--\r\nStream failed connection!!\r\n--");
+
+ // Hack to just restart it, you'll want to handle this nicer :)
+ [self.stream performSelector:@selector(start) withObject:nil afterDelay:10];
+}
+
+@end
View
0 TwitterStreams/en.lproj/InfoPlist.strings → ExampleApp/en.lproj/InfoPlist.strings
File renamed without changes.
View
0 TwitterStreams/en.lproj/ViewController.xib → ExampleApp/en.lproj/ViewController.xib
File renamed without changes.
View
0 TwitterStreams/main.m → ExampleApp/main.m
File renamed without changes.
View
146 TwitterStreams.xcodeproj/project.pbxproj
@@ -10,34 +10,52 @@
E07C43371505BB3F006279FA /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E07C43361505BB3F006279FA /* UIKit.framework */; };
E07C43391505BB3F006279FA /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E07C43381505BB3F006279FA /* Foundation.framework */; };
E07C433B1505BB3F006279FA /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E07C433A1505BB3F006279FA /* CoreGraphics.framework */; };
- E07C43411505BB3F006279FA /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = E07C433F1505BB3F006279FA /* InfoPlist.strings */; };
- E07C43431505BB3F006279FA /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = E07C43421505BB3F006279FA /* main.m */; };
- E07C43471505BB3F006279FA /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = E07C43461505BB3F006279FA /* AppDelegate.m */; };
- E07C434A1505BB3F006279FA /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E07C43491505BB3F006279FA /* ViewController.m */; };
- E07C434D1505BB3F006279FA /* ViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = E07C434B1505BB3F006279FA /* ViewController.xib */; };
+ E07C43601505BB6C006279FA /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = E07C43551505BB6C006279FA /* AppDelegate.m */; };
+ E07C43611505BB6C006279FA /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = E07C43561505BB6C006279FA /* InfoPlist.strings */; };
+ E07C43621505BB6C006279FA /* ViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = E07C43581505BB6C006279FA /* ViewController.xib */; };
+ E07C43631505BB6C006279FA /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = E07C435A1505BB6C006279FA /* main.m */; };
+ E07C43651505BB6C006279FA /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E07C435E1505BB6C006279FA /* ViewController.m */; };
+ E07C436A1505BC12006279FA /* TSStream.m in Sources */ = {isa = PBXBuildFile; fileRef = E07C43691505BC12006279FA /* TSStream.m */; };
+ E07C436C1505BC77006279FA /* Twitter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E07C436B1505BC77006279FA /* Twitter.framework */; };
+ E07C436E1505BC7C006279FA /* Accounts.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E07C436D1505BC7C006279FA /* Accounts.framework */; };
+ E07C43761505BF2C006279FA /* JSONKit.m in Sources */ = {isa = PBXBuildFile; fileRef = E07C43731505BF2C006279FA /* JSONKit.m */; };
+ E07C437A1505BFA9006279FA /* TSUserStream.m in Sources */ = {isa = PBXBuildFile; fileRef = E07C43791505BFA9006279FA /* TSUserStream.m */; };
+ E07C43811505DA4F006279FA /* TSFilterStream.m in Sources */ = {isa = PBXBuildFile; fileRef = E07C43801505DA4F006279FA /* TSFilterStream.m */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
E07C43321505BB3F006279FA /* TwitterStreams.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TwitterStreams.app; sourceTree = BUILT_PRODUCTS_DIR; };
E07C43361505BB3F006279FA /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
E07C43381505BB3F006279FA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
E07C433A1505BB3F006279FA /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
- E07C433E1505BB3F006279FA /* TwitterStreams-Info.plist */ = {isa = PBXFileReference; path = "TwitterStreams-Info.plist"; sourceTree = "<group>"; };
- E07C43401505BB3F006279FA /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
- E07C43421505BB3F006279FA /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
- E07C43441505BB3F006279FA /* TwitterStreams-Prefix.pch */ = {isa = PBXFileReference; path = "TwitterStreams-Prefix.pch"; sourceTree = "<group>"; };
- E07C43451505BB3F006279FA /* AppDelegate.h */ = {isa = PBXFileReference; path = AppDelegate.h; sourceTree = "<group>"; };
- E07C43461505BB3F006279FA /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
- E07C43481505BB3F006279FA /* ViewController.h */ = {isa = PBXFileReference; path = ViewController.h; sourceTree = "<group>"; };
- E07C43491505BB3F006279FA /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; };
- E07C434C1505BB3F006279FA /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/ViewController.xib; sourceTree = "<group>"; };
+ E07C43541505BB6C006279FA /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
+ E07C43551505BB6C006279FA /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
+ E07C43571505BB6C006279FA /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
+ E07C43591505BB6C006279FA /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/ViewController.xib; sourceTree = "<group>"; };
+ E07C435A1505BB6C006279FA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
+ E07C435B1505BB6C006279FA /* TwitterStreams-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "TwitterStreams-Info.plist"; sourceTree = "<group>"; };
+ E07C435C1505BB6C006279FA /* TwitterStreams-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "TwitterStreams-Prefix.pch"; sourceTree = "<group>"; };
+ E07C435D1505BB6C006279FA /* ViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = "<group>"; };
+ E07C435E1505BB6C006279FA /* ViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; };
+ E07C43681505BC12006279FA /* TSStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSStream.h; sourceTree = "<group>"; };
+ E07C43691505BC12006279FA /* TSStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSStream.m; sourceTree = "<group>"; };
+ E07C436B1505BC77006279FA /* Twitter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Twitter.framework; path = System/Library/Frameworks/Twitter.framework; sourceTree = SDKROOT; };
+ E07C436D1505BC7C006279FA /* Accounts.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accounts.framework; path = System/Library/Frameworks/Accounts.framework; sourceTree = SDKROOT; };
+ E07C43721505BF2C006279FA /* JSONKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSONKit.h; sourceTree = "<group>"; };
+ E07C43731505BF2C006279FA /* JSONKit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSONKit.m; sourceTree = "<group>"; };
+ E07C43781505BFA9006279FA /* TSUserStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSUserStream.h; sourceTree = "<group>"; };
+ E07C43791505BFA9006279FA /* TSUserStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSUserStream.m; sourceTree = "<group>"; };
+ E07C437F1505DA4F006279FA /* TSFilterStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSFilterStream.h; sourceTree = "<group>"; };
+ E07C43801505DA4F006279FA /* TSFilterStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSFilterStream.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
E07C432F1505BB3F006279FA /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ E07C436E1505BC7C006279FA /* Accounts.framework in Frameworks */,
+ E07C436C1505BC77006279FA /* Twitter.framework in Frameworks */,
E07C43371505BB3F006279FA /* UIKit.framework in Frameworks */,
E07C43391505BB3F006279FA /* Foundation.framework in Frameworks */,
E07C433B1505BB3F006279FA /* CoreGraphics.framework in Frameworks */,
@@ -50,7 +68,8 @@
E07C43271505BB3F006279FA = {
isa = PBXGroup;
children = (
- E07C433C1505BB3F006279FA /* TwitterStreams */,
+ E07C43531505BB6C006279FA /* ExampleApp */,
+ E07C435F1505BB6C006279FA /* TwitterStreams */,
E07C43351505BB3F006279FA /* Frameworks */,
E07C43331505BB3F006279FA /* Products */,
);
@@ -67,35 +86,76 @@
E07C43351505BB3F006279FA /* Frameworks */ = {
isa = PBXGroup;
children = (
+ E07C436D1505BC7C006279FA /* Accounts.framework */,
+ E07C436B1505BC77006279FA /* Twitter.framework */,
E07C43361505BB3F006279FA /* UIKit.framework */,
E07C43381505BB3F006279FA /* Foundation.framework */,
E07C433A1505BB3F006279FA /* CoreGraphics.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
- E07C433C1505BB3F006279FA /* TwitterStreams */ = {
+ E07C43531505BB6C006279FA /* ExampleApp */ = {
isa = PBXGroup;
children = (
- E07C43451505BB3F006279FA /* AppDelegate.h */,
- E07C43461505BB3F006279FA /* AppDelegate.m */,
- E07C43481505BB3F006279FA /* ViewController.h */,
- E07C43491505BB3F006279FA /* ViewController.m */,
- E07C434B1505BB3F006279FA /* ViewController.xib */,
- E07C433D1505BB3F006279FA /* Supporting Files */,
+ E07C43541505BB6C006279FA /* AppDelegate.h */,
+ E07C43551505BB6C006279FA /* AppDelegate.m */,
+ E07C43561505BB6C006279FA /* InfoPlist.strings */,
+ E07C43581505BB6C006279FA /* ViewController.xib */,
+ E07C435A1505BB6C006279FA /* main.m */,
+ E07C435B1505BB6C006279FA /* TwitterStreams-Info.plist */,
+ E07C435C1505BB6C006279FA /* TwitterStreams-Prefix.pch */,
+ E07C435D1505BB6C006279FA /* ViewController.h */,
+ E07C435E1505BB6C006279FA /* ViewController.m */,
+ );
+ path = ExampleApp;
+ sourceTree = "<group>";
+ };
+ E07C435F1505BB6C006279FA /* TwitterStreams */ = {
+ isa = PBXGroup;
+ children = (
+ E07C436F1505BE99006279FA /* Dependencies */,
+ E07C43661505BBD9006279FA /* Models */,
+ E07C43671505BBD9006279FA /* Streams */,
);
path = TwitterStreams;
sourceTree = "<group>";
};
- E07C433D1505BB3F006279FA /* Supporting Files */ = {
+ E07C43661505BBD9006279FA /* Models */ = {
+ isa = PBXGroup;
+ children = (
+ );
+ path = Models;
+ sourceTree = "<group>";
+ };
+ E07C43671505BBD9006279FA /* Streams */ = {
+ isa = PBXGroup;
+ children = (
+ E07C43681505BC12006279FA /* TSStream.h */,
+ E07C43691505BC12006279FA /* TSStream.m */,
+ E07C43781505BFA9006279FA /* TSUserStream.h */,
+ E07C43791505BFA9006279FA /* TSUserStream.m */,
+ E07C437F1505DA4F006279FA /* TSFilterStream.h */,
+ E07C43801505DA4F006279FA /* TSFilterStream.m */,
+ );
+ path = Streams;
+ sourceTree = "<group>";
+ };
+ E07C436F1505BE99006279FA /* Dependencies */ = {
+ isa = PBXGroup;
+ children = (
+ E07C43701505BF2C006279FA /* JSONKit */,
+ );
+ path = Dependencies;
+ sourceTree = "<group>";
+ };
+ E07C43701505BF2C006279FA /* JSONKit */ = {
isa = PBXGroup;
children = (
- E07C433E1505BB3F006279FA /* TwitterStreams-Info.plist */,
- E07C433F1505BB3F006279FA /* InfoPlist.strings */,
- E07C43421505BB3F006279FA /* main.m */,
- E07C43441505BB3F006279FA /* TwitterStreams-Prefix.pch */,
+ E07C43721505BF2C006279FA /* JSONKit.h */,
+ E07C43731505BF2C006279FA /* JSONKit.m */,
);
- name = "Supporting Files";
+ path = JSONKit;
sourceTree = "<group>";
};
/* End PBXGroup section */
@@ -149,8 +209,8 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- E07C43411505BB3F006279FA /* InfoPlist.strings in Resources */,
- E07C434D1505BB3F006279FA /* ViewController.xib in Resources */,
+ E07C43611505BB6C006279FA /* InfoPlist.strings in Resources */,
+ E07C43621505BB6C006279FA /* ViewController.xib in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -161,27 +221,31 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- E07C43431505BB3F006279FA /* main.m in Sources */,
- E07C43471505BB3F006279FA /* AppDelegate.m in Sources */,
- E07C434A1505BB3F006279FA /* ViewController.m in Sources */,
+ E07C43601505BB6C006279FA /* AppDelegate.m in Sources */,
+ E07C43631505BB6C006279FA /* main.m in Sources */,
+ E07C43651505BB6C006279FA /* ViewController.m in Sources */,
+ E07C436A1505BC12006279FA /* TSStream.m in Sources */,
+ E07C43761505BF2C006279FA /* JSONKit.m in Sources */,
+ E07C437A1505BFA9006279FA /* TSUserStream.m in Sources */,
+ E07C43811505DA4F006279FA /* TSFilterStream.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
- E07C433F1505BB3F006279FA /* InfoPlist.strings */ = {
+ E07C43561505BB6C006279FA /* InfoPlist.strings */ = {
isa = PBXVariantGroup;
children = (
- E07C43401505BB3F006279FA /* en */,
+ E07C43571505BB6C006279FA /* en */,
);
name = InfoPlist.strings;
sourceTree = "<group>";
};
- E07C434B1505BB3F006279FA /* ViewController.xib */ = {
+ E07C43581505BB6C006279FA /* ViewController.xib */ = {
isa = PBXVariantGroup;
children = (
- E07C434C1505BB3F006279FA /* en */,
+ E07C43591505BB6C006279FA /* en */,
);
name = ViewController.xib;
sourceTree = "<group>";
@@ -236,8 +300,8 @@
isa = XCBuildConfiguration;
buildSettings = {
GCC_PRECOMPILE_PREFIX_HEADER = YES;
- GCC_PREFIX_HEADER = "TwitterStreams/TwitterStreams-Prefix.pch";
- INFOPLIST_FILE = "TwitterStreams/TwitterStreams-Info.plist";
+ GCC_PREFIX_HEADER = "ExampleApp/TwitterStreams-Prefix.pch";
+ INFOPLIST_FILE = "ExampleApp/TwitterStreams-Info.plist";
PRODUCT_NAME = "$(TARGET_NAME)";
WRAPPER_EXTENSION = app;
};
@@ -247,8 +311,8 @@
isa = XCBuildConfiguration;
buildSettings = {
GCC_PRECOMPILE_PREFIX_HEADER = YES;
- GCC_PREFIX_HEADER = "TwitterStreams/TwitterStreams-Prefix.pch";
- INFOPLIST_FILE = "TwitterStreams/TwitterStreams-Info.plist";
+ GCC_PREFIX_HEADER = "ExampleApp/TwitterStreams-Prefix.pch";
+ INFOPLIST_FILE = "ExampleApp/TwitterStreams-Info.plist";
PRODUCT_NAME = "$(TARGET_NAME)";
WRAPPER_EXTENSION = app;
};
View
7 TwitterStreams.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+ version = "1.0">
+ <FileRef
+ location = "self:TwitterStreams.xcodeproj">
+ </FileRef>
+</Workspace>
1 TwitterStreams/Dependencies/JSONKit
@@ -0,0 +1 @@
+Subproject commit 0aff3deb5e1bb2bbc88a83fd71c8ad5550185cce
View
33 TwitterStreams/Streams/TSFilterStream.h
@@ -0,0 +1,33 @@
+//
+// TSFilterStream.h
+// TwitterStreams
+//
+// Created by Stuart Hall on 6/03/12.
+// Copyright (c) 2012 Filter Squad. All rights reserved.
+//
+
+#import "TSStream.h"
+
+@interface TSFilterStream : TSStream
+
+/*!
+ @method initWithAccount:andDelegate:andKeywords:
+
+ @abstract
+ Initialises and starts a stream
+
+ @param
+ account The authenticated account.
+
+ @param
+ delegate The delegate.
+
+ @param
+ keywords Keywords to filter on
+
+ */
+- (id)initWithAccount:(ACAccount*)account
+ andDelegate:(id<TSStreamDelegate>)delegate
+ andKeywords:(NSArray*)keywords;
+
+@end
View
26 TwitterStreams/Streams/TSFilterStream.m
@@ -0,0 +1,26 @@
+//
+// TSFilterStream.m
+// TwitterStreams
+//
+// Created by Stuart Hall on 6/03/12.
+// Copyright (c) 2012 Filter Squad. All rights reserved.
+//
+
+#import "TSFilterStream.h"
+
+@implementation TSFilterStream
+
+- (id)initWithAccount:(ACAccount*)account
+ andDelegate:(id<TSStreamDelegate>)delegate
+ andKeywords:(NSArray*)keywords {
+ NSMutableDictionary* parameters = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+ [keywords componentsJoinedByString:@","], @"track",
+ nil];
+
+ return [super initWithEndpoint:@"https://stream.twitter.com/1/statuses/filter.json"
+ andParameters:parameters
+ andAccount:account
+ andDelegate:delegate];
+}
+
+@end
View
34 TwitterStreams/Streams/TSStream.h
@@ -0,0 +1,34 @@
+//
+// TSStream.h
+//
+// Created by Stuart Hall on 6/03/12.
+// Copyright (c) 2012 Filter Squad. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+@class TSStream;
+@class ACAccount;
+
+@protocol TSStreamDelegate <NSObject>
+
+@optional
+
+- (void)streamDidReceiveMessage:(TSStream*)stream json:(id)json;
+- (void)streamDidReceiveInvalidJson:(TSStream*)stream message:(NSString*)message;
+- (void)streamDidTimeout:(TSStream*)stream;
+- (void)streamDidFailConnection:(TSStream*)stream;
+
+@end
+
+@interface TSStream : NSObject
+
+- (id)initWithEndpoint:(NSString*)endpoint
+ andParameters:(NSDictionary*)parameters
+ andAccount:(ACAccount*)account
+ andDelegate:(id<TSStreamDelegate>)delegate;
+
+- (void)start;
+- (void)stop;
+
+@end
View
174 TwitterStreams/Streams/TSStream.m
@@ -0,0 +1,174 @@
+//
+// TSStream.m
+//
+// Created by Stuart Hall on 6/03/12.
+// Copyright (c) 2012 Filter Squad. All rights reserved.
+//
+
+#import "TSStream.h"
+#import "JSONKit.h"
+
+#import <Twitter/Twitter.h>
+#import <Accounts/Accounts.h>
+
+@interface TSStream ()
+
+@property (nonatomic, retain) NSURLConnection* connection;
+@property (nonatomic, retain) NSTimer* keepAliveTimer;
+@property (nonatomic, assign) id<TSStreamDelegate> delegate;
+@property (nonatomic, retain) ACAccount* account;
+@property (nonatomic, retain) NSMutableDictionary* parameters;
+@property (nonatomic, retain) NSString* endpoint;
+
+@end
+
+@implementation TSStream
+
+@synthesize connection=_connection;
+@synthesize keepAliveTimer=_keepAliveTimer;
+@synthesize delegate=_delegate;
+@synthesize account=_account;
+@synthesize parameters=_parameters;
+@synthesize endpoint=_endpoint;
+
+- (void)dealloc {
+ [self.connection cancel];
+ self.connection = nil;
+
+ [self.keepAliveTimer invalidate];
+ self.keepAliveTimer = nil;
+
+ self.account = nil;
+ self.parameters = nil;
+ self.endpoint = nil;
+
+ [super dealloc];
+}
+
+- (id)initWithEndpoint:(NSString*)endpoint
+ andParameters:(NSDictionary*)parameters
+ andAccount:(ACAccount*)account
+ andDelegate:(id<TSStreamDelegate>)delegate {
+ self = [super init];
+ if (self) {
+ // Save the parameters
+ self.delegate = delegate;
+ self.account = account;
+ self.endpoint = endpoint;
+
+ // Use length delimited so we can count the bytes
+ self.parameters = [NSMutableDictionary dictionaryWithDictionary:parameters];
+ [self.parameters setObject:@"length" forKey:@"delimited"];
+ }
+ return self;
+}
+
+#pragma mark - Public methods
+
+- (void)start {
+ // Our actually request
+ TWRequest *request = [[TWRequest alloc]
+ initWithURL:[NSURL URLWithString:self.endpoint]
+ parameters:self.parameters
+ requestMethod:TWRequestMethodPOST];
+
+ // Set the current account for authentication, or even just rate limit
+ [request setAccount:self.account];
+
+ // Use the signed request to start a connection
+ self.connection = [NSURLConnection connectionWithRequest:request.signedURLRequest
+ delegate:self];
+
+ // Start the keepalive timer and connection
+ [self resetKeepalive];
+ [self.connection start];
+
+ [request release];
+}
+
+- (void)stop {
+ [self.connection cancel];
+ self.connection = nil;
+}
+
+#pragma mark - Keep Alive
+
+- (void)resetKeepalive {
+ [self.keepAliveTimer invalidate];
+ self.keepAliveTimer = [NSTimer scheduledTimerWithTimeInterval:40
+ target:self
+ selector:@selector(onTimeout)
+ userInfo:nil
+ repeats:NO];
+}
+
+- (void)onTimeout {
+ // Timeout
+ [self stop];
+
+ if (self.delegate && [self.delegate respondsToSelector:@selector(streamDidTimeout:)])
+ [self.delegate streamDidTimeout:self];
+
+ // Try and restart
+ [self start];
+}
+
+#pragma mark - NSURLConnectionDelegate
+
+- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
+ int bytesExpected = 0;
+ NSMutableString* message = nil;
+
+ NSString* response = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease];
+ for (NSString* part in [response componentsSeparatedByString:@"\r\n"]) {
+ int length = [part intValue];
+ if (length > 0) {
+ // New message
+ message = [NSMutableString string];
+ bytesExpected = length;
+ }
+ else if (bytesExpected > 0 && message) {
+ if (message.length < bytesExpected) {
+ // Append the data
+ [message appendString:part];
+
+ if (message.length < bytesExpected) {
+ // Newline counts
+ [message appendString:@"\r\n"];
+ }
+
+ if (message.length == bytesExpected) {
+ // Success!
+ id json = [message objectFromJSONString];
+
+ // Alert the delegate
+ if (json) {
+ if (self.delegate && [self.delegate respondsToSelector:@selector(streamDidReceiveMessage:json:)])
+ [self.delegate streamDidReceiveMessage:self json:json];
+ [self resetKeepalive];
+ }
+ else {
+ if (self.delegate && [self.delegate respondsToSelector:@selector(streamDidReceiveInvalidJson:message:)])
+ [self.delegate streamDidReceiveInvalidJson:self message:message];
+ }
+
+ // Reset
+ message = nil;
+ bytesExpected = 0;
+ }
+ }
+ }
+ else {
+ // Keep alive
+ [self resetKeepalive];
+ }
+ }
+}
+
+- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
+ if (self.delegate && [self.delegate respondsToSelector:@selector(streamDidFailConnection:)])
+ [self.delegate streamDidFailConnection:self];
+
+}
+
+@end
View
36 TwitterStreams/Streams/TSUserStream.h
@@ -0,0 +1,36 @@
+//
+// TSUserStream.h
+// TwitterStreams
+//
+// Created by Stuart Hall on 6/03/12.
+// Copyright (c) 2012 Filter Squad. All rights reserved.
+//
+
+#import "TSStream.h"
+
+@interface TSUserStream : TSStream
+
+/*!
+ @method initWithAccount:andDelegate:andAllReplies:andAllFollowings:
+
+ @abstract
+ Initialises and starts a stream
+
+ @param
+ account The authenticated account.
+
+ @param
+ delegate The delegate.
+
+ @param
+ allReplies YES for all replies, NO for mutual followings. [see here](https://dev.twitter.com/docs/streaming-api/user-streams)
+
+ @param
+ andAllFollowings YES for all following, NO for only the authenticated user. [see here](https://dev.twitter.com/docs/streaming-api/user-streams)
+ */
+- (id)initWithAccount:(ACAccount*)account
+ andDelegate:(id<TSStreamDelegate>)delegate
+ andAllReplies:(BOOL)allReplies
+ andAllFollowings:(BOOL)allFollowing;
+
+@end
View
29 TwitterStreams/Streams/TSUserStream.m
@@ -0,0 +1,29 @@
+//
+// TSUserStream.m
+// TwitterStreams
+//
+// Created by Stuart Hall on 6/03/12.
+// Copyright (c) 2012 Filter Squad. All rights reserved.
+//
+
+#import "TSUserStream.h"
+
+@implementation TSUserStream
+
+- (id)initWithAccount:(ACAccount*)account
+ andDelegate:(id<TSStreamDelegate>)delegate
+ andAllReplies:(BOOL)allReplies
+ andAllFollowings:(BOOL)allFollowing {
+ NSMutableDictionary* parameters = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+ allFollowing ? @"followings" : @"user", @"with",
+ nil];
+ if (allReplies)
+ [parameters setObject:@"all" forKey:@"replies"];
+
+ return [super initWithEndpoint:@"https://userstream.twitter.com/2/user.json"
+ andParameters:parameters
+ andAccount:account
+ andDelegate:delegate];
+}
+
+@end
View
34 TwitterStreams/ViewController.m
@@ -1,34 +0,0 @@
-//
-// ViewController.m
-// TwitterStreams
-//
-// Created by Stuart Hall on 6/03/12.
-// Copyright (c) 2012 Filter Squad. All rights reserved.
-//
-
-#import "ViewController.h"
-
-@interface ViewController ()
-
-@end
-
-@implementation ViewController
-
-- (void)viewDidLoad
-{
- [super viewDidLoad];
- // Do any additional setup after loading the view, typically from a nib.
-}
-
-- (void)viewDidUnload
-{
- [super viewDidUnload];
- // Release any retained subviews of the main view.
-}
-
-- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
-{
- return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
-}
-
-@end

0 comments on commit 1d435db

Please sign in to comment.