I have the following code which is used on my View Controller whenever its property 'document' (of type UIManagedDocument) is set.
I'm not sure if other people do, but I find the notion of concurrency in Core Data very confusing, the documents have a go at explaining it but it's still hard to get to grips with. For this reason, I was wondering if people had any ideas of how to speed up the code I use for saving the newly set UIDocument if it does not exist. This code does work, if others would like to use it.
My main goal is to try and make the time it takes for the document to save and load much faster. It currently takes about 20 seconds to do this, which is way too long!
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
if (![[NSFileManager defaultManager] fileExistsAtPath:self.documentDatabase.fileURL.path]) {
[self.documentDatabase saveToURL:self.documentDatabase.fileURL
forSaveOperation:UIDocumentSaveForCreating
completionHandler:^(BOOL success) {
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
if (success) {
NSLog(#"Saved %#", self.documentDatabase.localizedName);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self.documentDatabase.managedObjectContext performBlockAndWait:^{
dispatch_async(dispatch_get_main_queue(), ^{
[Book newBookWithTitle:self.documentDatabase.fileURL.lastPathComponent.stringByDeletingPathExtension inManagedObjectContext:self.documentDatabase.managedObjectContext];
[self saveDocumentWithCompletionHandler:^(bool success) {
if (success) {
[self setIsDocumentHidden:NO];
}
}];
NSLog(#"Added default note to %#", self.documentDatabase.fileURL.lastPathComponent);
});
}];
});
} else {
NSLog(#"Error saving %#", self.documentDatabase.fileURL.lastPathComponent);
}
}];
} else {
[self openDocumentWithCompletionHandler:nil];
}
20 seconds sounds a bit extreme, unless you're dealing with a vast database. Have you tried Time Profiling the saving process in Instruments?
Even if the delay is entirely within framework code, sometimes by diving deep into the time profile you can get some hint of what it's doing that is taking so long. For example, its only tangentially related, but by doing this I discovered saving UIManagedDocuments that were synced over iCloud were totally clobbered performance wise by the presence of inverse relationships in the data model.
Related
I'm using AFNetworking and MagicalRecord (the current develop branch) and I'm trying to figure out how to import a lot of objects which are dependent on each other. Each resource/entity has multiple pages worth of downloads. I have a class managing the downloads for a given entity and saving them using MagicalDataImport (which has been amazing).
I believe my issue is that the imports aren't happening on the same thread. So I think what is happening is:
In one thread, EntityA is getting saved properly and propagated to the parent entity.
Then in another thread, EntityB is being saved, and along with it it's relationship to EntityA is built. That means a blank (fault?) object is being created. Then when it gets propagated to the parent entity, I believe EntityA is overwriting the EntityA that is there. Thus I'm left with some objects that don't have all of the attributes.
At least, I think that is what is happening. What I'm seeing via the UI is actually that the relationships between entities aren't always built correctly.
My end goal is to get the entire download/import process to be done in the background, not effecting the UI at all.
Here is my AFJSONRequest:
AFJSONRequestOperation *operation = [AFJSONRequestOperation
JSONRequestOperationWithRequest:request
success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON)
{
[self saveResources:[JSON objectForKey:#"data"]];
}
failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON)
{
DLog(#"%#",error.userInfo);
[self.webService command:self didFail:error.localizedDescription];
}];
[operation setQueuePriority:self.priority];
And it calls saveResources::
- (void)saveResources:(NSArray*)resources {
BOOL stopDownloads = [self stopDownloadsBasedOnDate:resources];
if ([resources count] > 0 && !stopDownloads){
self.offset = #([offset intValue] + [resources count]);
[self send];
}
[MagicalRecord saveWithBlock:^(NSManagedObjectContext *blockLocalContext) {
[self.classRef MR_importFromArray:resources inContext:blockLocalContext];
} completion:^(BOOL success, NSError *error) {
if (error){
// ... handle errors
}
else {
// ... handle callbacks
}
}];
}
This kicks off another download ([self send]) and then saves the objects.
I know by default AFNetworking calls the callback in the main queue, and I've tried setting the SuccessCallbackQueue/FailureCallbackQueue to my background thread, but that doesn't seem to solve all the issues, I still have some relationships going to faulted objects, though I think I do need to do that to keep everything going in a background thread.
Is there anything else I need to call in order to properly propagate these changes to the main context? Or is there a different way I need to set this up in order to make sure that all the objects are saved correctly and the relationships are properly built?
Update
I've rewritten the issue to try to give more clarification to the issues.
Update
If you need more code I created a gist with (I believe) everything.
I ended up having this exact same issue a few days ago. My issue was I had received a customer record from my API with AFNetworking. That customer could have pets, but at this point I didn't have the petTypes to correspond to the customers pet record.
What I did to resolve this was create a transformable attribute with an NSArray which would temporarly store my pets until my petTypes were imported. Upon the importation of petTypes I then triggered an NSNotificationCenter postNotification (or you can just do the pet import in the completion).
I enumerated through the temporary transformable attribute that stored my pet records and then associated the with the petType
Also I see you are doing your import inside of a save handler. This is not needed. Doing your MR_importFromArray will save automatically. If you are not using an MR_import method then you would use the saveToPersistentStore methods.
One thing is I don't see where you are associating the relationships. Is EntityB's relationship to EntityA being sent over via JSON with the EntityA objecting being in EntityB?
If so then this is where the relationship is getting messed up as it is creating / overwriting the existing EntityA for the one provided in EntityB. My recommendation would be to do something like this.
NSArray *petFactors = [responseObject valueForKeyPath:#"details.items"];
NSManagedObjectContext *currentContext = [NSManagedObjectContext MR_context];
Pets *pet = [Pets MR_findFirstByAttribute:#"id" withValue:petId inContext:currentContext];
pet.petFactors = nil;
for (id factor in petFactors) {
[pet addPetFactorsObject:[PetFactors MR_findFirstByAttribute:#"id" withValue:[factor valueForKey:#"factorId"]]];
}
[currentContext MR_saveToPersistentStoreWithCompletion:^(BOOL success, NSError *error) {
if (success) {
NSLog(#"SAVED PET FACTORS");
[[NSNotificationCenter defaultCenter] postNotificationName:kPetFactorsSavedSuccessfully object:nil];
} else {
NSLog(#"Error: %#", error);
}
}];
I'm putting this as an answer, though I'm not 100% sure if this is your issue or not. I think the issue stems from your localContext. Here is a sample web request method from an app we wrote that uses data importing, you may be able to use it as an example to get yours working.
Note that the AFNetworking performs its completion block on the main thread, then the MagicalRecord saveInBackground method switches back to a background thread to do the importing and processing, then the final MR completion block performs the handler block on the main thread again. The localContext that's used to import is created/managed by the saveInBackground method. Once that method is complete the context is saved and merged with the app's main context and all the data can then be accessed.
- (void)listWithCompletionHandler:(void (^)(BOOL success))handler{
[[MyAPIClient sharedClient] getPath:#"list.json" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject){
NSString *statusString = [responseObject objectForKey:#"status"];
// Handle an error response
if(![statusString isKindOfClass:[NSString class]] || ![statusString isEqualToString:#"success"]){
// Request failure
NSLog(#"List Request Error: %#", statusString);
NSLog(#"%#", [responseObject objectForKey:#"message"]);
if(handler)
handler(NO);
return;
}
NSArray *itemsArray = [responseObject objectForKey:#"items"];
[MagicalRecord saveInBackgroundWithBlock:^(NSManagedObjectContext *localContext){
// Load into internal database
NSArray *fetchedItems = [Item importFromArray:itemsArray inContext:localContext];
NSLog(#"Loaded %d Items", [fetchedItems count]);
} completion:^{
if(handler)
handler(YES);
}];
} failure:^(AFHTTPRequestOperation *operation, NSError *error){
NSLog(#"Fail: %#", error);
if(handler)
handler(NO);
}];
}
I have created few entities in context for saving it in db using
AppCalendarEntity *appCalendar = [AppCalendarEntity getInstanceWithManagedDocument:manageDocument];
After adding a few entities I execute flowing fetch request
NSFetchRequest *requestToSeeIfCalendarWithIdExist = [NSFetchRequest fetchRequestWithEntityName:#"AppCalendarEntity"];
NSArray *result = [managedDocument.managedObjectContext executeFetchRequest:requestToSeeIfCalendarWithIdExist error:&InternalError] ;
It returns me the result including only the entities I have added in context using first command and NOT the entries already saved in database. I have made sure that at this stage the document state is UIDocumentStateNormal.
When I add this line to already open document (UIDocumentStateNormal) it returns me the expected result, i.e. it fetch results from db as well as memory context which has not yet been saved to db.
[managedDocument openWithCompletionHandler:^(BOOL success)
{
NSFetchRequest *requestToSeeIfCalendarWithIdExist = [NSFetchRequest fetchRequestWithEntityName:#"AppCalendarEntity"];
NSArray *result = [managedDocument.managedObjectContext executeFetchRequest:requestToSeeIfCalendarWithIdExist error:&InternalError] ;
}
My question is
1- I expect that the result of query should be the same in both cases. Why it is not so in the above case.
2- To me if document state is UIDocumentStateNormal I should not be calling "openWithCompletionHandler" in context to open the document. In this particular scenario what difference it is making in NSFetchRequest which gives me the desired result after adding this.
Please let me know if I'm getting wrong
Here is the complete code
This is the complete code of the function
+ (void ) saveCalendarArrayInDbIfItAlreadyDoesNotExist : (NSArray*) appCalendarArray managedDocument: (UIManagedDocument*) managedDocument completionBlock : ( void(^) (NSArray* ObjectSavedSuccesfully, NSError *InternalError)) handler
{
// i dont know why i have to do it :( if i dont add openWithCompletionHandler my query doesnt fetch result from db rather just do query in-memory context and not db
[managedDocument openWithCompletionHandler:^(BOOL success)
{
void (^completionHandler)(NSArray* , NSError* );
completionHandler = [handler copy ];
NSError *error = nil;
NSMutableArray *array = [[NSMutableArray alloc] init];
for (id appCalendar in appCalendarArray) {
if([appCalendar isKindOfClass:[AppCalendarEntity class]])
{
AppCalendarEntity *appCalendarEntity = (AppCalendarEntity*) appCalendar;
NSFetchRequest *requestToSeeIfCalendarWithIdExist = [NSFetchRequest fetchRequestWithEntityName:#"MyEntity"];
requestToSeeIfCalendarWithIdExist.predicate = [NSPredicate predicateWithFormat:#"identifier = %#", appCalendarEntity.identifier];
NSError *InternalError = nil;
[requestToSeeIfCalendarWithIdExist setShouldRefreshRefetchedObjects:YES];
NSArray *result = [managedDocument.managedObjectContext executeFetchRequest:requestToSeeIfCalendarWithIdExist error:&InternalError] ;
// "result" is different when we encapsulate it in openWithCompletionHandler and when we don't…….MY PROBLEM
if(result == nil)
{
// return error
}
// 1 object always return that depict the in memory(context) object we created but not saved. I expect it should be zero because no object has yet been saved to database..
else if(result.count > 1)
{
[managedDocument.managedObjectContext deleteObject:appCalendar];
}
else
{
[array addObject:appCalendarEntity];
}
}
else
{
// error handling
}
}
if (error != nil)
{
completionHandler (nil, error);
return;
}
// saving all the objects
[ managedDocument updateChangeCount:UIDocumentChangeDone ];
}
When using UIManagedDocument, you do not call save on the MOC because it implements auto-save. however, it needs to be told that an auto-save should take place at some point in the future.
Get rid of that call to openWithCompletionHandler in that function (I know it was just there for purposes of debugging this problem).
Replace
[managedDocument.managedObjectContext save:&InternalError ]
with
[managedDocument updateChangeCount:UIDocumentChangeDone];
This will notify the document that it can now be saved.
EDIT
First, I think you should get rid of the debugging hacks. You can add NSLog or NSAssert, but the rest of that stuff just makes it hard to tell why you want, and confuses the real issue.
Second, what is your real goal here? I can see the name of the method, and I can see the code, but they do not match.
There is so much "cruft" here, it is hard to understand your problem. I am going to repost your code, along with an edit to remove the "open" stuff, and annotate it with questions as code comments.
Hopefully, this change will help you solve your problem.
// First, the method name seems to indicate that some objects will be added
// to the database. however, the only database work in this method is removal.
// I don't get it.
+ (void ) saveCalendarArrayInDbIfItAlreadyDoesNotExist : (NSArray*) appCalendarArray managedDocument: (UIManagedDocument*) managedDocument
{
NSError *error = nil;
NSMutableArray *array = [[NSMutableArray alloc] init];
for (id appCalendar in appCalendarArray) {
if([appCalendar isKindOfClass:[AppCalendarEntity class]]) {
// OK, we are filtering the array of objects. We are only interested in
// objects of type AppCalendarEntity, and are going to use its identity
// property to look for objects of type MyEntity.
// What is the relationship between AppCalendarEntity and MyEntity?
AppCalendarEntity *appCalendarEntity = (AppCalendarEntity*) appCalendar;
NSFetchRequest *requestToSeeIfCalendarWithIdExist = [NSFetchRequest fetchRequestWithEntityName:#"MyEntity"];
requestToSeeIfCalendarWithIdExist.predicate = [NSPredicate predicateWithFormat:#"identifier = %#", appCalendarEntity.identifier];
NSError *InternalError = nil;
[requestToSeeIfCalendarWithIdExist setShouldRefreshRefetchedObjects:YES];
NSArray *result = [managedDocument.managedObjectContext executeFetchRequest:requestToSeeIfCalendarWithIdExist error:&InternalError];
// OK, now we just got a result from searching for a MyEntity, where
// its identifier is the same as the appCalendarEntity.
if(result == nil)
{
// return error
}
// 1 object always return that depict the in memory(context) object we created but not saved. I expect it should be zero because no object has yet been saved to database..
else if(result.count > 1)
{
// I am extremely confused by this code. First, why are you
// checking for more than 1 object? The method name indicates
// you are going to insert something. Furthermore, you are only
// deleting one object. How many do you expect? Also, why are
// you deleting an appCalendar? You were searching for a MyEntity.
// If an appCalendar is a MyEntity, then that's terrible naming.
// Furthermore, it would explain why you are finding it...
// because you create entities by inserting them in a MOC to
// begin with!
[managedDocument.managedObjectContext deleteObject:appCalendar];
}
else
{
// Even more confusion. You are adding this object to an internal
// array, not the database. Furthermore, you are doing it if there
// are either 0 or 1 MyEntity objects in the database with matching
// identifier.
[array addObject:appCalendarEntity];
}
}
}
// saving all the objects
// OK - but the only thing being saved are the ones you deleted...
[ managedDocument updateChangeCount:UIDocumentChangeDone ];
}
Finally, if my hunch is correct, and the calendar objects are actually MyEntity objects, they are already in the MOC - because that's how they get created. When you do a fetch, you can force the search to ignore pending changes (as noted in one of my previous comments) and only accept saved changes.
If you want to ignore pending changes,
fetchRequest.includesPendingChanges = NO;
#Jody Problem has been resolved and thank you for giving time to this question.
First let me address your confusions
1- Yes function is intended to save in the database and it is a helping function. The parameter "appCalendarArray" being passed to this function consist of entities that has already been created in context. I intentionally eliminated the logic since it involves communicating with external apis, parsing json etc etc. The code required for inserting entities in context has already been included in first part of the question.
AppCalendarEntity *appCalendar = [AppCalendarEntity getInstanceWithManagedDocument:manageDocument];
2- I eliminate the entities from context which has been constructed but not yet saved from context, based upon a column in database that should be unique. If we have identifier for object already in database, we do not want to resave it. So, I simply delete it from context. This function works as expected, entities are not re-saved in database. The last line do save the objects that are left in context if any. Most of the time there are a lot.
3- Sorry for mistyping AppCalendarEntity and MyEntity are the same.
Solution
I have added this flag fetchRequest.includesPendingChanges = NO; , delete db, restarted Xcode and it started working. Thank you for your persistence
I have an NSPersistentDocument subclass using NSManagedObject subclasses for my data.
When a new document is opened, I do some initializing of data structures (trivial amount of populating fields). What I've noticed is that the Untitled document gets autosaved, and when the application re-opens, that document gets loaded. If the application quits, the user doesn't (by default) get prompted with the save dialog. If the window closes, the user does.
First question:
I want to call up the save dialog when the user quits the application. I don't want this Untitled document hanging around (under normal circumstances). I either want it saved or trashed.
I attempted to fill out:
- (void)applicationWillTerminate:(NSNotification *)aNotification
In order to trigger the document to be saved. Calling save: on the context at this point gives an error. From what I can tell, this is because the user hasn't yet saved the file on their own. In addition, calling [self close]; or [[self windowForSheet] close]; close the window without saving.
How can I force the save dialog to come up? How can I trash the untitled document?
Second question (no, I can't count):
Since when the application starts, there may or may not be an Untitled document to deal with, I'm trying to keep track of the state in another model. I've already found that the initial data (to which I referred earlier) is present when the Untitled document came up. My other model has some metadata, including a success flag/state for the populated data. Once the populated data is all in place and correct, the state indicates as such. Unfortunately, while my populated data is being loaded when the app starts with a pre-existing Untitled document, the metadata class is not.
Please excuse the roughness of the code, at this point, I'm mucking it up until I can see that it's working how I want before I polish it back off:
- (bool) createGameState {
NSEntityDescription* description = [NSEntityDescription entityForName:[GameState name] inManagedObjectContext:[self managedObjectContext]];
NSFetchRequest* req = [[NSFetchRequest alloc] init];
[req setEntity:description];
NSError *error = nil;
NSArray *array = [[self managedObjectContext] executeFetchRequest:req error:&error];
[req release];
req = nil;
GameState* result = nil;
if (array) {
NSUInteger count = [array count];
if (!count) {
// Create the new GameState.
DebugLog(#"Creating GameState");
result = [NSEntityDescription insertNewObjectForEntityForName:[GameState name] inManagedObjectContext:[self managedObjectContext]];
[result setIsLoaded:[NSNumber numberWithBool:NO]];
} else {
if (count > 1) {
NSLog(#"WARNING: Potentially Corrupt Game State. found: %lu", count);
}
result = [array objectAtIndex:0];
if ([result isLoaded]) {
[self variantLoaded];
} else {
// In this case, we have an aborted set-up. Since the game isn't
// playable, just refuse to create the GameState. This will
// force the user to create a new game.
return NO;
}
}
} else {
DebugLog(#"error: %#", error);
}
[game setState:result];
return result;
}
Note that array is always present, and count is always zero. No, I'm not explicitly calling save: anywhere. I'm relying on the standard auto-save, or the user performing a save.
EDIT:
I installed the Core Data Editor app. It turns out the issue isn't on saving the data, but on loading it. (Note: Due to another issue, the app saves as binary when instructed to save as XML, which causes much head banging.)
I've broken it down to the simplest code, which should pick up all objects of type GameState in an array. It retrieves none, despite there clearly being objects of the appropriate type in the saved file:
NSManagedObjectContext* moc = [self managedObjectContext];
NSEntityDescription* entity = [NSEntityDescription entityForName:#"GameState" inManagedObjectContext:moc];
NSFetchRequest* req = [[NSFetchRequest alloc] init];
[req setEntity:entity];
NSError *error = nil;
NSArray *array = [moc executeFetchRequest:req error:&error];
Array is not null, but [array count] is 0.
At this point, I'm guessing it's something simple that I'm overlooking.
Second EDIT:
I added -com.apple.CoreData.SQLDebug 5 and saved as SQLite. The call to executeFetchRequest does not generate any debug logs. I do see the INSERT INTO ZGAMESTATE entry show up in the logs. It seems that executeFetchRequest is not getting passed to the backend.
Third EDIT (this one burns):
I created a new xcode project, using core data (as I had with the other). I copied just this one function (stubbing where necessary) and plopped a call to it in windowControllerDidLoadNib. In this new project, the code above works.
Found the problem.
I errantly was loading objects in Document's - (id) init call. Moved to windowControllerDidLoadNib (which is what I did in the test version) and it worked fine.
I make a program where I sometimes moves some anchor to another
When I move those anchors I would recompute distance of bizs nearby the 2 anchors (before and after anchors). The computation is done in background
I used this standard code to update stuff
+(void)commit {
// get the moc for this thread
[Tools breakIfLock];
NSManagedObjectContext *moc = [self managedObjectContext];
NSThread *thread = [NSThread currentThread];
DLog(#"threadKey commit%#" , [[self class]threadKey]);
if ([thread isMainThread] == NO) {
// only observe notifications other than the main thread
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(contextDidSave:) name:NSManagedObjectContextDidSaveNotification object:moc];
}
NSError *error;
if (![moc save:&error]) {
CLog(#"Error in Saving %#", error);
DLog(#"What the hell error is it");
}
else{
}
if ([thread isMainThread] == NO) {
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSManagedObjectContextDidSaveNotification object:moc];
}
//[GrabClass StopNetworkActivityIndicatorVisible];
}
+(void)contextDidSave:(NSNotification*)saveNotification {
dispatch_async(dispatch_get_main_queue(), ^{
BadgerNewAppDelegate *delegate = [BNUtilitiesQuick appDelegate];
DLog (#"currentThreadinContextDidSave: %#",[self threadKey]);
NSManagedObjectContext *moc = delegate.managedObjectContext; //delegate for main object
CLog(#"saveNotification : %#",saveNotification);
[moc mergeChangesFromContextDidSaveNotification:saveNotification];
});
//[moc performSelectorOnMainThread:#selector(mergeChangesFromContextDidSaveNotification:) withObject:saveNotification waitUntilDone:YES];
}
I break point and see that distances did get updated. Everything is fine
However the NSFetchedResultsController fetchedObjects doesn't seem to get updated and still use the old value.
How can that be?
Also the
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
DLog(#"controllerWillChangeContent: %#", controller);
[self.tableViewA beginUpdates];
}
is never called even though the NSManagedObjectContext has changes.
Well actually I wasn't sure if the managedObjectContext has changed or not. How do I know? I mean will change in managedObjectContext ensure changes in fetchController.fetchedObjects.
There is no caching as far as I know. How can I be sure of that too?
The NSFetchedResultsController documentation for fetchedObjects property states:
The results array only includes instances of the entity specified by
the fetch request (fetchRequest) and that match its predicate. (If the
fetch request has no predicate, then the results array includes all
instances of the entity specified by the fetch request.)
The results array reflects the in-memory state of managed objects in
the controller’s managed object context, not their state in the
persistent store. The returned array does not, however, update as
managed objects are inserted, modified, or deleted.
Availability Available in iOS 3.0 and later.
I can't say what the appropriate workaround is. My first thought is to call performFetch: in controllerDidChangeContent: in the delegate implementation.
The fetchedObjects array appears to update simply by overriding controllerDidChangeContent: with an empty implementation. This is the case using both the iPad and the iPad simulator for iOS 5.1.
There's clearly some discrepancy between the documentation and what I have observed. I have no explanation. Sorry. I can only suggest that you perform the fetch in controllerDidChangeContent: just to be safe.
I've been teaching myself Objective-C over the past few months; I'm building an iPhone app for my company. I started as (and still am) a complete novice, but until now I have had no problems easily finding answers to all my questions at various locations online.
For the final, and most important, piece of my app, I need to send a simple string to an address/port via UDP when a button is pressed. The string, address, and port are all variables pulled from an object passed to my view controller.
I have been digging around for two days looking at solutions and reading examples, but everything seriously reads like Greek to me. I'm not sure what major hunk of knowledge I seem to have missed out on, but I'm at a total loss. I learned about cocoaasyncsocket, and how "simple" it is, and it sounds perfect for what I need, but I just can't seem to wrap my mind around it. I'm really hoping someone here can help break it down for me into simple terms.
Here is a snippet of the code I've been trying, but with no luck. This code is from my viewController, with AsyncUdpSocket.h imported:
-(IBAction)udpButtonTwoPressed:(id)sender {
NSData *myData;
myData = [[NSData alloc] initWithData:([selectedObject
valueForKey:#"udpCommandTwo"])];
AsyncUdpSocket *mySocket;
mySocket = [[AsyncUdpSocket alloc] initWithDelegate:self ];
NSError *error = nil;
if (!([mySocket connectToHost:([selectedObject
valueForKey:#"serverIPAddress"]) onPort:([[selectedObject
valueForKey:#"serverPort"] intValue]) error:&error])) {
NSLog(#"Can't Connect Cause: %#", error);
abort();
}
[mySocket close];
[mySocket release];
[myData release];
}
What am I doing wrong here?
There are two things that stand out from your example.
I don't see you writing anything to the socket. Have a look at writeData:withTimeout:tag.
CocoaAsyncSocket is asynchronous so in your example everything is going out of scope. If you are really wanted to write synchronously there is an example in the reference.
NSString *customRunLoopMode = #"MySyncWrite";
[asyncSocket addRunLoopMode:customRunLoopMode];
[asyncSocket writeData:didBackgroundData withTimeout:TIMEOUT_NONE tag:TAG_BG];
syncWriteComplete = NO;
BOOL runLoopReady = YES;
while (runLoopReady && !syncWriteComplete)
{
runLoopReady = [[NSRunLoop currentRunLoop] runMode:customRunLoopMode
beforeDate:[NSDate dateWithTimeIntervalSinceNow:1.0]];
}
[asyncSocket removeRunLoopMode:customRunLoopMode];
HTH