shlist

share and manage lists between multiple people
Log | Files | Refs

commit fe97754c45294ddf5927a86b6bfcc2c257cbadfe
parent 77b642144cfff5008542dd9b7f61ce7d5ed80b95
Author: Kyle Milz <kyle@green.krwm.net>
Date:   Sat, 20 Feb 2016 15:23:23 -0700

ios: misc cleanups

- fix ~20 warnings
- remove duplicated code in Network.m
- assign notification requests with functions better
- {input,output}ShlistStream -> {input,output}_stream
- add a read_all function in Network.m

Diffstat:
Mios/ContactsTableViewController.m | 12++++++------
Mios/EditItemTableViewController.m | 2+-
Mios/shlist.xcodeproj/project.pbxproj | 8--------
Mios/shlist/AppDelegate.m | 8++++++--
Mios/shlist/ListTableViewController.m | 4++--
Mios/shlist/MainTableViewController.m | 49+++++++++++++++++++++----------------------------
Mios/shlist/Network.h | 7+++----
Mios/shlist/Network.m | 172++++++++++++++++++++++++++++++++++---------------------------------------------
8 files changed, 112 insertions(+), 150 deletions(-)

diff --git a/ios/ContactsTableViewController.m b/ios/ContactsTableViewController.m @@ -76,8 +76,8 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { - int section = [indexPath section]; - int row = [indexPath row]; + NSInteger section = [indexPath section]; + NSInteger row = [indexPath row]; Contact *contact = [[_cells objectAtIndex:section] objectAtIndex:row]; UITableViewCell *cell; @@ -117,8 +117,8 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { - int section = [indexPath section]; - int row = [indexPath row]; + NSInteger section = [indexPath section]; + NSInteger row = [indexPath row]; [tableView deselectRowAtIndexPath:indexPath animated:YES]; @@ -142,8 +142,8 @@ [cell setAccessoryType:UITableViewCellAccessoryNone]; } - NSLog(@"info: selected %@ %@ who has %i phone numbers", - contact.first_name, contact.last_name, [contact.phone_numbers count]); + NSLog(@"info: selected %@ %@ who has %lu phone numbers", + contact.first_name, contact.last_name, (unsigned long)[contact.phone_numbers count]); } // programatically assign section headers, in this case they're letters diff --git a/ios/EditItemTableViewController.m b/ios/EditItemTableViewController.m @@ -123,7 +123,7 @@ [buffer appendData:[[string_array componentsJoinedByString:@":"] dataUsingEncoding:NSUTF8StringEncoding]]; // the list item that was just edited will be updated when a response comes - [network_connection send_message:7 contents:buffer]; + //[network_connection send_message:7 contents:buffer]; NSLog(@"debug: %@: %@: saving", _list.name, _item.name); } diff --git a/ios/shlist.xcodeproj/project.pbxproj b/ios/shlist.xcodeproj/project.pbxproj @@ -22,8 +22,6 @@ 27C70F301B33F4FA00DADEB3 /* MainTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 27C70F2F1B33F4FA00DADEB3 /* MainTableViewController.m */; }; 27D805731BA2649D00867494 /* ContactsTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 27D805721BA2649D00867494 /* ContactsTableViewController.m */; }; 27D83D2A1BAFC99D0029F54B /* EditTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 27D83D291BAFC99D0029F54B /* EditTableViewController.m */; }; - 27DCC9DE1B8A98D400207340 /* dollar103-2.png in Resources */ = {isa = PBXBuildFile; fileRef = 27DCC9DD1B8A98D400207340 /* dollar103-2.png */; }; - 27DCC9E81B9EB4E800207340 /* information15-3.png in Resources */ = {isa = PBXBuildFile; fileRef = 27DCC9E71B9EB4E800207340 /* information15-3.png */; }; 27DCC9EB1B9FF89E00207340 /* AddressBook.m in Sources */ = {isa = PBXBuildFile; fileRef = 27DCC9EA1B9FF89E00207340 /* AddressBook.m */; }; BF7776B91B38928D00526CB0 /* ListTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = BF7776B81B38928D00526CB0 /* ListTableViewController.m */; }; /* End PBXBuildFile section */ @@ -68,8 +66,6 @@ 27D805721BA2649D00867494 /* ContactsTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ContactsTableViewController.m; sourceTree = SOURCE_ROOT; }; 27D83D281BAFC99D0029F54B /* EditTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EditTableViewController.h; sourceTree = "<group>"; }; 27D83D291BAFC99D0029F54B /* EditTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EditTableViewController.m; sourceTree = "<group>"; }; - 27DCC9DD1B8A98D400207340 /* dollar103-2.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "dollar103-2.png"; path = "../../../Downloads/dollar103-2.png"; sourceTree = "<group>"; }; - 27DCC9E71B9EB4E800207340 /* information15-3.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "information15-3.png"; path = "../../../Downloads/information15-3.png"; sourceTree = "<group>"; }; 27DCC9E91B9FF89E00207340 /* AddressBook.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AddressBook.h; sourceTree = "<group>"; }; 27DCC9EA1B9FF89E00207340 /* AddressBook.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AddressBook.m; sourceTree = "<group>"; }; BF7776B71B38928D00526CB0 /* ListTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ListTableViewController.h; sourceTree = "<group>"; }; @@ -126,13 +122,11 @@ 27D805721BA2649D00867494 /* ContactsTableViewController.m */, 27C70F281B33CE2500DADEB3 /* DataStructures.h */, 27C70F291B33D1C900DADEB3 /* DataStructures.m */, - 27DCC9DD1B8A98D400207340 /* dollar103-2.png */, 27AAC22A1B50ABAF00D99171 /* EditItemTableViewController.h */, 27AAC22B1B50ABAF00D99171 /* EditItemTableViewController.m */, 27D83D281BAFC99D0029F54B /* EditTableViewController.h */, 27D83D291BAFC99D0029F54B /* EditTableViewController.m */, 27C70F0F1B32AF8000DADEB3 /* Images.xcassets */, - 27DCC9E71B9EB4E800207340 /* information15-3.png */, 27C70F111B32AF8000DADEB3 /* LaunchScreen.xib */, BF7776B71B38928D00526CB0 /* ListTableViewController.h */, BF7776B81B38928D00526CB0 /* ListTableViewController.m */, @@ -259,9 +253,7 @@ files = ( 27C70F0E1B32AF8000DADEB3 /* Main.storyboard in Resources */, 27C70F131B32AF8000DADEB3 /* LaunchScreen.xib in Resources */, - 27DCC9E81B9EB4E800207340 /* information15-3.png in Resources */, 27C70F101B32AF8000DADEB3 /* Images.xcassets in Resources */, - 27DCC9DE1B8A98D400207340 /* dollar103-2.png in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/ios/shlist/AppDelegate.m b/ios/shlist/AppDelegate.m @@ -38,7 +38,9 @@ NSMutableDictionary *request = [[NSMutableDictionary alloc] init]; [request setObject:hex_token forKey:@"pushtoken_hex"]; - [network_connection send_message:device_update contents:request]; + if ([network_connection get_device_id] != nil) { + [network_connection send_message:device_update contents:request]; + } } // Called when push notification received @@ -96,7 +98,9 @@ // background. NSLog(@"info: app: entering foreground, reconnecting..."); - [network_connection send_message:lists_get contents:[[NSMutableDictionary alloc] init]]; + [network_connection connect]; + //[network_connection send_message:lists_get contents:[[NSMutableDictionary alloc] init]]; + //[network_connection send_message:lists_get_other contents:[[NSMutableDictionary alloc] init]]; } - (void) applicationDidBecomeActive:(UIApplication *)application diff --git a/ios/shlist/ListTableViewController.m b/ios/shlist/ListTableViewController.m @@ -170,9 +170,9 @@ - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { if (section == 0) - return [NSString stringWithFormat:@"Shared Items (%i)", [_list_items count]]; + return [NSString stringWithFormat:@"Shared Items (%lu)", (unsigned long)[_list_items count]]; else if (section == 1) - return [NSString stringWithFormat:@"Private Items (%i)", [_private_items count]]; + return [NSString stringWithFormat:@"Private Items (%lu)", (unsigned long)[_private_items count]]; return @""; } diff --git a/ios/shlist/MainTableViewController.m b/ios/shlist/MainTableViewController.m @@ -43,32 +43,25 @@ [default_center addObserver:self selector:@selector(push_updated_list:) name:@"PushNotification_updated_list" object:nil]; - // Hook up generic message handlers - notification_name = [NSString stringWithFormat:@"NetworkResponseForMsgType%i", lists_get]; - [default_center addObserver:self selector:@selector(lists_get_finished:) - name:notification_name object:nil]; - - notification_name = [NSString stringWithFormat:@"NetworkResponseForMsgType%i", lists_get_other]; - [default_center addObserver:self selector:@selector(lists_get_other_finished:) - name:notification_name object:nil]; - - notification_name = [NSString stringWithFormat:@"NetworkResponseForMsgType%i", list_add]; - [default_center addObserver:self selector:@selector(finished_new_list_request:) - name:notification_name object:nil]; - - notification_name = [NSString stringWithFormat:@"NetworkResponseForMsgType%i", list_join]; - [default_center addObserver:self selector:@selector(finished_join_list_request:) - name:notification_name object:nil]; - - notification_name = [NSString stringWithFormat:@"NetworkResponseForMsgType%i", list_leave]; - [default_center addObserver:self selector:@selector(finished_leave_list_request:) - name:notification_name object:nil]; - + const SEL selectors[] = { + @selector(lists_get_finished:), + @selector(lists_get_other_finished:), + @selector(finished_new_list_request:), + @selector(finished_join_list_request:), + @selector(finished_leave_list_request:) + }; + NSUInteger count = 0; + + // This object handles responses for these types of messages + for (id str in @[@"lists_get", @"lists_get_other", @"list_add", @"list_join", @"list_leave"]) { + notification_name = [NSString stringWithFormat:@"NetworkResponseFor_%@", str]; + [default_center addObserver:self selector:selectors[count] name:notification_name object:nil]; + count++; + } // display an Edit button in the navigation bar for this view controller self.navigationItem.leftBarButtonItem = self.editButtonItem; - // there's a race here when assigning self network_connection = [Network shared_network_connection]; _lists = [[NSMutableArray alloc] init]; @@ -227,7 +220,7 @@ clickedButtonAtIndex:(NSInteger)buttonIndex { } -- (void) lists_get_finished:(NSNotification *)notification; +- (void) lists_get_finished:(NSNotification *)notification { NSDictionary *response = notification.userInfo; @@ -252,7 +245,7 @@ clickedButtonAtIndex:(NSInteger)buttonIndex { NSDictionary *response = notification.userInfo; NSArray *other_json_lists = [response objectForKey:@"other_lists"]; - NSLog(@"lists_get_other: got %i other lists from server", [other_json_lists count]); + NSLog(@"lists_get_other: got %lu other lists from server", (unsigned long)[other_json_lists count]); NSMutableArray *other_lists = [_lists objectAtIndex:1]; [other_lists removeAllObjects]; @@ -510,14 +503,14 @@ titleForHeaderInSection:(NSInteger)section UITableViewCell *cell; cell = [tableView dequeueReusableCellWithIdentifier:@"SharedListPrototypeCell" forIndexPath:indexPath]; - int section = [indexPath section]; - int row = [indexPath row]; + NSInteger section = [indexPath section]; + NSInteger row = [indexPath row]; SharedList *shared_list = [[_lists objectAtIndex:section] objectAtIndex:row]; UILabel *deadline_label = (UILabel *)[cell viewWithTag:3]; UILabel *fraction_label = (UILabel *)[cell viewWithTag:4]; - if ([indexPath section] == 0) { + if (section == 0) { // your lists section if (shared_list.date == nil) { @@ -539,7 +532,7 @@ titleForHeaderInSection:(NSInteger)section cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; } - else if ([indexPath section] == 1) { + else if (section == 1) { // "other lists" section // no deadline diff --git a/ios/shlist/Network.h b/ios/shlist/Network.h @@ -3,8 +3,8 @@ #import "MsgTypes.h" @interface Network : NSObject <NSStreamDelegate> { - NSInputStream *inputShlistStream; - NSOutputStream *outputShlistStream; + NSInputStream *input_stream; + NSOutputStream *output_stream; } - (void) connect; @@ -19,4 +19,4 @@ // returns singleton instance + (id) shared_network_connection; -@end -\ No newline at end of file +@end diff --git a/ios/shlist/Network.m b/ios/shlist/Network.m @@ -55,27 +55,23 @@ CFWriteStreamRef writeStream; CFStringRef host_name = CFSTR("absentmindedproductions.ca"); - CFStreamCreatePairWithSocketToHost(NULL, host_name, 9999, &readStream, &writeStream); - inputShlistStream = (__bridge NSInputStream *)readStream; - outputShlistStream = (__bridge NSOutputStream *)writeStream; - [inputShlistStream setDelegate:self]; - [outputShlistStream setDelegate:self]; + input_stream = (__bridge NSInputStream *)readStream; + output_stream = (__bridge NSOutputStream *)writeStream; - [inputShlistStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; - [outputShlistStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; + [input_stream setDelegate:self]; + [output_stream setDelegate:self]; - // Enable SSL on both streams - [inputShlistStream setProperty:NSStreamSocketSecurityLevelTLSv1 forKey:NSStreamSocketSecurityLevelKey]; - [outputShlistStream setProperty:NSStreamSocketSecurityLevelTLSv1 forKey:NSStreamSocketSecurityLevelKey]; + [input_stream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; + [output_stream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; - [inputShlistStream open]; - [outputShlistStream open]; + // Enable SSL on both streams + [input_stream setProperty:NSStreamSocketSecurityLevelTLSv1 forKey:NSStreamSocketSecurityLevelKey]; + [output_stream setProperty:NSStreamSocketSecurityLevelTLSv1 forKey:NSStreamSocketSecurityLevelKey]; - NSLog(@"network: connect()"); - connected = 1; - [[NSNotificationCenter defaultCenter] postNotificationName:@"NetworkConnectedNotification" object:nil userInfo:nil]; + [input_stream open]; + [output_stream open]; } - (void) disconnect @@ -84,16 +80,16 @@ connected = 0; [[NSNotificationCenter defaultCenter] postNotificationName:@"NetworkDisconnectedNotification" object:nil userInfo:nil]; - [inputShlistStream close]; - [outputShlistStream close]; + [input_stream close]; + [output_stream close]; - [inputShlistStream removeFromRunLoop:[NSRunLoop currentRunLoop] + [input_stream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; - [outputShlistStream removeFromRunLoop:[NSRunLoop currentRunLoop] + [output_stream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; - inputShlistStream = nil; // stream is ivar, so reinit it - outputShlistStream = nil; // stream is ivar, so reinit it + input_stream = nil; // stream is ivar, so reinit it + output_stream = nil; // stream is ivar, so reinit it } - (bool) load_device_id:(NSString *)phone_number; @@ -113,44 +109,21 @@ } // no device id file found, send a registration message - NSMutableData *msg = [NSMutableData data]; - - NSDictionary *request = [NSDictionary dictionaryWithObjectsAndKeys: + NSMutableDictionary *request = [NSMutableDictionary dictionaryWithObjectsAndKeys: phone_number, @"phone_number", @"ios", @"os", nil]; + [self send_message:device_add contents:request]; - NSError *error = nil; - NSData *json = [NSJSONSerialization dataWithJSONObject:request options:0 error:&error]; - if (error != nil) { - NSLog(@"%@", [error userInfo]); - return false; - } - - uint16_t version = htons(0); - uint16_t msg_type = htons(device_add); - uint16_t length = htons([json length]); - [msg appendBytes:&version length:2]; - [msg appendBytes:&msg_type length:2]; - [msg appendBytes:&length length:2]; - - // Append JSON payload - [msg appendData:json]; - - [outputShlistStream write:[msg bytes] maxLength:[msg length]]; - NSLog(@"register: sent request"); - - // we don't have a device id so we can't do anything yet return false; } - (bool) send_message:(uint16_t)send_msg_type contents:(NSMutableDictionary *)request { - if (!connected) - [self connect]; - - // Append 'device_id' to all message requests sent through this function - [request setObject:device_id forKey:@"device_id"]; + if (send_msg_type != device_add) { + // Append 'device_id' to all message types except device_add + [request setObject:device_id forKey:@"device_id"]; + } NSError *error = nil; // Try to serialize request, bail if errors @@ -172,20 +145,10 @@ [msg appendBytes:&length length:2]; [msg appendData:json]; - NSLog(@"network: send_message: type %i, %i bytes", - send_msg_type, [msg length]); - - if ([outputShlistStream write:[msg bytes] maxLength:[msg length]] == -1) { - NSLog(@"network: write error occurred, trying reconnect"); - if (connected) - [self disconnect]; - [self connect]; + NSLog(@"network: send_message: type %i, %lu bytes", + send_msg_type, (unsigned long)[msg length]); - if ([outputShlistStream write:[msg bytes] maxLength:[msg length]] == -1) { - NSLog(@"network: resend failed after reconnect, giving up"); - return false; - } - } + [output_stream write:[msg bytes] maxLength:[msg length]]; // sent successfully return true; @@ -194,10 +157,10 @@ - (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode { NSString *stream_name; - if (stream == inputShlistStream) - stream_name = @"input"; - else if (stream == outputShlistStream) - stream_name = @"output"; + if (stream == input_stream) + stream_name = @"input stream"; + else if (stream == output_stream) + stream_name = @"output stream"; switch (eventCode) { case NSStreamEventNone: { @@ -206,39 +169,41 @@ } case NSStreamEventOpenCompleted: { NSLog(@"network: %@ opened", stream_name); + + connected = 1; + [[NSNotificationCenter defaultCenter] postNotificationName:@"NetworkConnectedNotification" object:nil userInfo:nil]; break; } case NSStreamEventHasBytesAvailable: { - NSLog(@"network: %@ has bytes available", stream_name); - - if (stream == inputShlistStream) { - if (![inputShlistStream hasBytesAvailable]) { - NSLog(@"read: input stream had no bytes available"); - break; - } + // NSLog(@"network: %@ has bytes available", stream_name); - [self read_ready]; + if (stream != input_stream) { + break; } + + // Read an entire message, header + payload + [self read_ready]; + break; } case NSStreamEventHasSpaceAvailable: { - NSLog(@"network: %@ has space available", stream_name); + // NSLog(@"network: %@ has space available", stream_name); break; } case NSStreamEventErrorOccurred: { // happens when trying to connect to a down server NSStream *error_stream; - if (stream == inputShlistStream) - error_stream = inputShlistStream; - else if (stream == outputShlistStream) - error_stream = outputShlistStream; + if (stream == input_stream) + error_stream = input_stream; + else if (stream == output_stream) + error_stream = output_stream; else // don't try to do operations on null stream break; NSError *theError = [error_stream streamError]; - NSLog(@"network: %@", [NSString stringWithFormat:@"%@ error %i: %@", - stream_name, [theError code], [theError localizedDescription]]); + NSLog(@"network: %@", [NSString stringWithFormat:@"%@ error %li: %@", + stream_name, (long)[theError code], [theError localizedDescription]]); [self disconnect]; @@ -255,20 +220,20 @@ } } +// Try to read and parse an entire message. If the messsage type isn't device_add, +// then send a notification to the classes responsible - (void) read_ready { - NSInteger buffer_len; + // Read header uint16_t header[3]; + [self read_all:(uint8_t *)header size:6]; - buffer_len = [inputShlistStream read:(uint8_t *)header maxLength:6]; - if (buffer_len != 6) { - NSLog(@"read: didn't return 6 bytes"); - } - + // Unpack header uint16_t version = ntohs(header[0]); uint16_t msg_type = ntohs(header[1]); uint16_t payload_size = ntohs(header[2]); + // Verify header if (version != 0) { NSLog(@"read: invalid version %i", version); return; @@ -278,20 +243,16 @@ return; } + // Read payload, accept up to 64KB of data uint8_t *payload = malloc(payload_size); + [self read_all:payload size:payload_size]; + NSLog(@"read: payload is %i bytes", payload_size); - // Accept up to 64KB of data, the maximum size of payload_size - buffer_len = [inputShlistStream read:payload maxLength:payload_size]; - if (buffer_len != payload_size) { - NSLog(@"read: expected %i byte payload but got %i", payload_size, buffer_len); - return; - } - NSLog(@"read: payload is %i bytes", buffer_len); - + // Create new NSData wrapper around the payload bytes NSData *data = [NSData dataWithBytesNoCopy:payload length:payload_size]; NSError *error = nil; - // Try to parse payload and check for errors + // Try to parse the payload as JSON, check for errors NSDictionary *response = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error]; if (error) { @@ -324,11 +285,24 @@ return; } - // Send a generic notification, these have to be hooked up to work - NSString *notification_name = [NSString stringWithFormat:@"NetworkResponseForMsgType%i", msg_type]; + // Send out a notification that a response was received. The responsible + // parties should already be listening for these by the time they come in. + NSString *notification_name = [NSString stringWithFormat:@"NetworkResponseFor_%s", msg_strings[msg_type]]; [[NSNotificationCenter defaultCenter] postNotificationName:notification_name object:nil userInfo:response]; } +// Read a fixed amount of bytes +- (NSInteger) read_all:(uint8_t *)data size:(unsigned int)size +{ + NSInteger buffer_len = [input_stream read:data maxLength:size]; + if (buffer_len != size) { + NSLog(@"read_all: read %ld instead of %d bytes", (long)buffer_len, size); + return buffer_len; + } + + return buffer_len; +} + - (void) dealloc { [self disconnect];