I am trying to make a app that can connect to a device and ask for a query. To be able to have the a reply, I need to send an NSString command first. I have it in a loop with NSTimer.
I normally have like this in Interface Builder
Read:
SIDDA1999AP
then after some time changed to
Read:
#REL10345
and so on until the last string send #"H\r\n" then back to the first one.
Part of my code base in Asyncsocket
- (void)viewDidLoad
{
[super viewDidLoad];
// Read Data as loaded
NSTimer *t;
t = [NSTimer scheduledTimerWithTimeInterval: 0.5
target: self
selector:#selector(onTick:)
userInfo: nil repeats:YES];
}
-(void)onTick:(NSTimer *)timer {
sendStr =
#"S\r"
#"#\r\n"
#"P\r\n"
#"H\r\n"
;
NSData *sendData = [sendStr dataUsingEncoding:NSUTF8StringEncoding];
[asyncSocket writeData:sendData withTimeout:-1.0 tag:0];
[asyncSocket readDataToData:[GCDAsyncSocket CRLFData] withTimeout:-1 tag:0];
}
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
DDLogVerbose(#"socket:didReadData:withTag:");
NSString *response = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
componentsSeparatedByString:#"L"]objectAtIndex:6];
[self debugPrint2:[NSString stringWithFormat:#"Read: \n%#",response]];
[response release];
[asyncSocket readDataWithTimeout:-1 tag:0];
}
debugPrint2 where I display my text.
I want to extract string from debugPrint and display it individually. Because its in a loop data would be dynamic. I also need to extract a substring (shorten from SIDDA1999AP to 1999). In other words, remove the prefix and suffix.
My xib would have like
Data1: 1999
Data2: 10345
....
Here's an image of my application in progress:
I hope somebody could help.
Related
Right to the point, then:
First snippet (AppDelegate):
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
//...code taken out...
[NSEvent addGlobalMonitorForEventsMatchingMask:NSKeyDownMask handler:^(NSEvent *incomingEvent) {
if ([incomingEvent type] == NSKeyDown) {
NSUInteger flags = [incomingEvent modifierFlags] & NSDeviceIndependentModifierFlagsMask;
if (flags==NSCommandKeyMask && ([incomingEvent keyCode] == 8)) {
[ClipboardUtilities logger:#"cmd+c recognized"];
[self determineAndAddToHistory];
}
}
}];
}
Second snippet (AppDelegate):
-(void) determineAndAddToHistory {
id clipDat = [ClipboardUtilities getClipboardDataNatively];
if ([clipDat isKindOfClass:[NSAttributedString class]])
NSLog(#"clipDat.string = %#",((NSAttributedString*)clipDat).string);
}
Third snippet (ClipboardUtilities class):
+(id) getClipboardDataNatively {
NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
NSArray *classArray = #[[NSAttributedString class], [NSImage class]];
NSDictionary *options = [NSDictionary dictionary];
NSArray *objectsToPaste = nil;
BOOL ok = [pasteboard canReadObjectForClasses:classArray options:options];
if (ok) {
objectsToPaste = [pasteboard readObjectsForClasses:classArray options:options];
}
NSLog(#"objectsToPaste count = %li",[objectsToPaste count]);
return [objectsToPaste objectAtIndex:0];
}
I've noticed some strange behaviour that I will try to explain with an example:
Input
Cmd+C the string "A"
Cmd+C the string "B"
Cmd+C the string "C"
Cmd+C the string "D"
Output from determineAndAddToHistory
A
A
B
C
So I'm noticing that it retains that first item for some reason...then returns me the second most recent item each time. I've tried outputting the objectsToPaste array in the getClipboardDataNatively method, and this still is the case. Could someone please let me know how I would approach this problem, or how they've solved it?
P.S. my ClipboardUtilities class does not implement any Delegates, or inherit from anything but NSObject.
Well I guess since nobody likes long questions (I'll have to figure out how to shorten this), I figured something out. For some reason, I get the hotkey call really quickly (the clipboard gets updated AFTER the key is called in fact). As a result, I just have a small delay, and my model is now updated properly:
NSTimer* briefDelay = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:#selector(determineAndAddToHistory) userInfo:nil repeats:NO];
[[NSRunLoop mainRunLoop] addTimer:briefDelay forMode:NSRunLoopCommonModes];
I do not invalidate the timer manually, as per the documentation:
repeats
If YES, the timer will repeatedly reschedule itself until invalidated. If NO, the timer will be invalidated after it fires.
I know its something to do with locks or dispatch groups, but I just cant seem to code it...
I need to know if the address was a valid address before leaving the method. Currently the thread just overruns and returns TRUE. I've tried locks, dispatchers the works but can't seem to get it correct. Any help appreciated:
- (BOOL) checkAddressIsReal
{
__block BOOL result = TRUE;
// Lets Build the address
NSString *location = [NSString stringWithFormat:#" %# %#, %#, %#, %#", streetNumberText.text, streetNameText.text, townNameText.text, cityNameText.text, countryNameText.text];
// Put a pin on it if it is valid
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder geocodeAddressString:location
completionHandler:^(NSArray* placemarks, NSError* error) {
result = [placemarks count] != 0;
}];
return result;
}
The documentation says that CLGeocoder calls the completionHandler on the main thread. Since you are probably also calling your method from the main thread it cannot wait for the geocoder's answer without giving it the opportunity to deliver the result.
That would be done by polling the runloop, using some API as -[NSRunLoop runMode:beforeDate:].
The disadvantage is that depending on the mode this will also deliver events and fire timers while waiting for the result.
Just use block as parameter:
- (void) checkAddressIsRealWithComplectionHandler:(void (^)(BOOL result))complectionHandler
{
__block BOOL result = TRUE;
// Lets Build the address
NSString *location = [NSString stringWithFormat:#" %# %#, %#, %#, %#", streetNumberText.text, streetNameText.text, townNameText.text, cityNameText.text, countryNameText.text];
// Put a pin on it if it is valid
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder geocodeAddressString:location
completionHandler:^(NSArray* placemarks, NSError* error) {
result = [placemarks count] != 0;
complectionHandler(result);
}];
}
Ok guys, I am fairly new to objective C. I have an app that downloads a list of images from my web server and displays the appropriate ones in a UIImage view with swipe gestures to go forward or backwards for the next/previous pic to be displayed. Current naming format for the pictures is like this:
uploaded_141_admin1.png
uploaded_141_admin2.png
uploaded_141_interior1.png
uploaded_141_interior2.png
uploaded_141_exterior1.png
The current code loads every picture into the view that has 141 in the middle part of the filename (or whatever record the user in on... 141 is variable in this instance, just showing here for an example of the format). The problem is, there seems to be no rhyme or reason as to what order they are displayed in. I would like it to use the last part of the filename to sort alphabetically (or even the whole filename, as it would achieve the same result). In the example above, it would display the downloaded pics in the following order when swiping through the uiimageiew:
uploaded_141_admin1.png
uploaded_141_admin2.png
uploaded_141_exterior1.png
uploaded_141_interior1.png
uploaded_141_interior2.png
I've search and can't find what I am looking for (maybe because I'm using the wrong search criteria). Here is my existing code that downloads and displays the images in the UIImageView. I assume the "sort" code would go in here somewhere:
-(void)downloadPictures:(NSArray *)picPaths {
ELog(#"Downloading pictures: %#",picPaths);
// wait indicator
[[WaitingView sharedInstance] setMessage:LocStr(#"Loading pictures... The more pictures there are, the longer this will take. Please be patient.")];
[[WaitingView sharedInstance] showIndicator:YES];
[[WaitingView sharedInstance] displayOn:[self view]];
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
// queue download operation
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSInvocationOperation *downloadOp = [[NSInvocationOperation alloc] initWithTarget:self selector:#selector(downloadOperation:) object:picPaths];
[queue addOperation:downloadOp];
}
-(void)downloadOperation:(NSArray *)picPaths {
NSMutableArray *allPictures = [[NSMutableArray alloc] init];
for(NSString *path in picPaths) {
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"http://%#%#/%#/%#",SERVER_ADDRESS,SERVER_PORT,SERVER_PHOTOS,path]];
NSData *picData = [NSData dataWithContentsOfURL:url];
if(picData!=nil) {
UIImage *img = [UIImage imageWithData:picData];
if(img!=nil) {
[allPictures addObject:img];
} else {
ELog(#"Failed to convert data to image from url %#",url);
}
} else {
ELog(#"Failed to download image from url %#",url);
}
}
[[WaitingView sharedInstance] performSelectorOnMainThread:#selector(remove) withObject:nil waitUntilDone:NO];
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
self.pictures=allPictures;
if([self.pictures count]==0) {
[self performSelectorOnMainThread:#selector(downloadErrorMessage) withObject:nil waitUntilDone:NO];
} else {
self.currentIndex=0;
[self performSelectorOnMainThread:#selector(showPicture) withObject:nil waitUntilDone:NO];
}
}
-(void)downloadErrorMessage {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Oooops!" message:LocStr(#"Pictures download failed") delegate:nil cancelButtonTitle:LocStr(#"Close") otherButtonTitles:nil];
[alert show];
[alert release];
[self goBack];
}
-(void)showPicture {
UIImage *image = [self.pictures objectAtIndex:self.currentIndex];
ELog(#"Now displaying image with index %d: %#",self.currentIndex,image);
self.picture.image=image;
[self.picture setNeedsLayout];
}
In your downloadPictures: method you should sort your picPaths array to be the order you want the images before you start the download operation. You can do this by creating a new sorted array using the NSArray method sortedArrayUsingSelector:. Using caseInsensitiveCompare: as the selector for the sort will order the NSStrings in the array alphabetically.
NSArray *sortedPicPaths = [picPaths sortedArrayUsingSelector:#selector(caseInsensitiveCompare:)];
Then when you init your NSInvocationOperation, pass the sorted array as the object.
Everybody..
I am trying to develop an app for iPhone which basicly deals with ABAddressBook and contacts data...
My goal is to send all the contacts data (at first step, names and phones) in a file by e-mail..
Now, I am trying to reach the contacts data, and I want to add them to two different arrays, names and phones arrays..
At first, I am trying to see all the datas in the screen when i pressed a button "List Contacts". the datas should be seen on the screen. and then when i pressed the second button "Send Contacts", it should send the file to an e-mail account.. This is how my apps will work..
I am having problems at showing the data on the screen.. I wrote something but it doesn't give anything on the screen in a textView..
Can you help me to solve this problem?
Here's the code for listing the contacts (listCon method):
-(IBAction)listCon:(id)sender
{
NSMutableArray *names = [[NSMutableArray alloc] init];
NSMutableArray *numbers1= [[NSMutableArray array] init];
NSMutableArray *numbers2= [[NSMutableArray array] init];
NSMutableArray *numbers3= [[NSMutableArray array] init];
ABAddressBookRef addressBook = ABAddressBookCreate();
if (addressBook != nil)
{
NSLog(#"Successfully accessed the address book.");
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook);
CFIndex nPeople= ABAddressBookGetPersonCount(addressBook);
NSUInteger peopleCounter = 0;
for (peopleCounter = 0;peopleCounter < nPeople; peopleCounter++)
{
ABRecordRef thisPerson = CFArrayGetValueAtIndex(allPeople,peopleCounter);
NSString *contactFirstLast = [NSString stringWithFormat:#"%,%",ABRecordCopyValue(thisPerson, kABPersonFirstNameProperty), ABRecordCopyValue(thisPerson,kABPersonLastNameProperty)];
[names insertObject:contactFirstLast atIndex:peopleCounter];
ABMultiValueRef phoneNumbers = ABRecordCopyValue(thisPerson,kABPersonPhoneProperty);
NSString *firstPhone = (__bridge_transfer NSString*) ABMultiValueCopyValueAtIndex(phoneNumbers, 0);
NSString *secondPhone = (__bridge_transfer NSString*) ABMultiValueCopyValueAtIndex(phoneNumbers, 1);
NSString *thirdPhone = (__bridge_transfer NSString*) ABMultiValueCopyValueAtIndex(phoneNumbers, 2);
[numbers1 insertObject:firstPhone atIndex:peopleCounter];
[numbers2 insertObject:secondPhone atIndex:peopleCounter];
[numbers3 insertObject:thirdPhone atIndex:peopleCounter];
}
}
myView.text=[names componentsJoinedByString:#"\n\n"];
myView.text=[numbers1 componentsJoinedByString:#"\n\n"];
myView.text=[numbers2 componentsJoinedByString:#"\n\n"];
myView.text=[numbers3 componentsJoinedByString:#"\n\n"];
}
Just glancing at your code, you can't do this:
NSString *contactFirstLast = [NSString stringWithFormat:#"%,%",ABRecordCopyValue(thisPerson, kABPersonFirstNameProperty), ABRecordCopyValue(thisPerson,kABPersonLastNameProperty)];
There are several errors: first off % in your stringWithFormat: is not a format specifier; you probably are thinking of %#. Second off, copying the value of kABPersonFirstNameProperty will return a CFStringRef, and that's not what you want to display the name in a text field. You'll have to toll-free bridge the result of ABRecordCopyValue(). You can do this by adding this line - (__bridge_transfer NSString *) - in front of your ABRecordCopyValue()'s. With all the corrections, it should look like this:
NSString *contactFirstLast = [NSString stringWithFormat:#"%#,%#", (__bridge_transfer NSString *)ABRecordCopyValue(thisPerson, kABPersonFirstNameProperty), (__bridge_transfer NSString *)ABRecordCopyValue(thisPerson,kABPersonLastNameProperty)];
Hope this help (might not cover all errors)!
Did a search but cant seem to find exactly what I'm looking for
Basically I load values into a nsmutablearray in one method and then I want to access these values in another method to print them to a table
I declared the array in the app.h
NSMutableArray *clients;
Then in the app.m
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[connection release];
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
[responseData release];
NSArray *results = [responseString JSONValue];
clients = [[NSMutableArray alloc]init];
// Loop through each entry and add clients to array
for (NSDictionary *entry in results)
{
if (![clients containsObject:[entry objectForKey:#"client"]])
{
[clients addObject:[entry objectForKey:#"client"]];
}
}
}
Now Im try to acces the clients array in another method
I have seen some suggestions to use extern in the app.h? Some sort of global variable?
Any help would be appreciated
Thanks
Take the clients array in app delegate class.declare the property,synthesizes in the app delegate class.Then in the below method write like this.
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[connection release];
YourApplicationDelegate *delegate = [UIApplication sharedApplication]delegate];
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
[responseData release];
NSArray *results = [responseString JSONValue];
clients = [[NSMutableArray alloc]init];
// Loop through each entry and add clients to array
for (NSDictionary *entry in results)
{
if (![clients containsObject:[entry objectForKey:#"client"]])
{
[delegate.clients addObject:[entry objectForKey:#"client"]];
}
}
}
after that suppose you if you want to use the clients array in another class do like this.
YourApplicationDelegate *delegate = [UIApplication sharedApplication]delegate];
NSLog(#"client array is %#",delegate.clients);