Handling duplicate selects in NSTokenField - objective-c

How do I prevent duplicate select from an Array in an NSTokenField. I've implemented the delegate completionsForSubstring.

I was able to remove any duplicates with this approach, which admittedly is a little hacky but it works:
// Be sure to set the delegate of your NSTokenfield either in IB or in code.
#pragma mark - NSTokenFieldDelegate
-(NSArray *)tokenField:(NSTokenField *)tokenField shouldAddObjects:(NSArray *)tokens atIndex:(NSUInteger)index{
double delayInSeconds = .1;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
NSArray *aray = [tokenField objectValue];
NSOrderedSet *set = [NSOrderedSet orderedSetWithArray:aray];
aray = [set array];
[tokenField setObjectValue:aray];
});
return tokens;
}

The best method I would say is to implement the delegate shouldAddObjects. Write the following code in the delegate.
NSString *newVal = [[tokens objectAtIndex:0] description];
NSArray *aray = [tokenField objectValue];
for (NSString * token in aray) {
#try{
if ([token isEqual:newVal]){
return nil;
}
}
#catch (NSException *exception) {
;
}
}

Related

EXC_BAD_ACCESS for an object created inside a Block

I have always been nervous when it comes to blocks and GCD because my mind tells me that it looks very complex!
I am getting a crash inside a block which ideally looks alright to me:
#pragma mark -
-(void)fetchOrdersListWithInfoDict:(NSDictionary*)infoDict completionBlock:(CompletionBlock)completionBlock errorBlock:(ErrorBlock)errorBlock
{
__weak VTVehicleServiceNetworkManager *weakSelf = self;
TaskBlock fetchOrdersListTaskBlock = ^()
{
__block __strong HLOrdersDataProvider *ordersDataProvider = nil;
NSBlockOperation *fetchOrdersOperation = [NSBlockOperation blockOperationWithBlock:[^{
ordersDataProvider = [[HLOrdersDataProvider alloc] init];
[ordersDataProvider performFetchOrdersListWithInfoDict:infoDict
completionBlock:completionBlock
errorBlock:errorBlock];
} copy]];
[weakSelf.dataOperationQueue addOperation:fetchOrdersOperation];
};
[self fetchDataWithTaskBlock:[fetchOrdersListTaskBlock copy]
errorBlock:^(NSError *error) {
errorBlock(error);
}];
}
I was able to trace out the zombie object but I am not able to figure out why is this object turning out to be a zombie. Here is the snapshot from profile:
I have gone through the following guides (1, 2) to see if I can find out what I am doing wrong but I was no where near to find out what is going wrong.
Any help and reference text to what I am doing wrong will help.
Edit:
I have tried what #Jerimy has suggested and in fact my code which I have posted earlier was exactly the same as required: Declaring and initializing ordersDataProvider inside the block operation itself. But since it was crashing at the same point I tried to declare it outside the block just to see if it addresses the crash.
Below is the new code I tested:
#pragma mark -
-(void)fetchOrdersListWithInfoDict:(NSDictionary*)infoDict completionBlock:(CompletionBlock)completionBlock errorBlock:(ErrorBlock)errorBlock
{
__weak VTVehicleServiceNetworkManager *weakSelf = self;
completionBlock = [completionBlock copy];
errorBlock = [errorBlock copy];
TaskBlock fetchOrdersListTaskBlock = ^()
{
NSBlockOperation *fetchOrdersOperation = [NSBlockOperation blockOperationWithBlock:^{
HLOrdersDataProvider *ordersDataProvider = [[HLOrdersDataProvider alloc] init];
[ordersDataProvider performFetchOrdersListWithInfoDict:infoDict
completionBlock:completionBlock
errorBlock:errorBlock];
}];
[weakSelf.dataOperationQueue addOperation:fetchOrdersOperation];
};
[self fetchDataWithTaskBlock:[fetchOrdersListTaskBlock copy]
errorBlock:^(NSError *error) {
errorBlock(error);
}];
}
The crash from Profile:
There is not much from the stack trace as well, SDMHTTPRequest is a library and am very sure there is nothing wrong there, and the HLOrdersDataProvider is the zombie object which I was able to trace out in Instruments app:
EDIT 2
Adding the interface and implementation of HLOrdersDataProvider for more details:
#interface HLOrdersDataProvider : HLDataProvider
-(void)performFetchOrdersListWithInfoDict:(NSDictionary*)infoDict completionBlock:(CompletionBlock)completionBlock errorBlock:(ErrorBlock)errorBlock;
#end
#implementation HLOrdersDataProvider
-(void)performFetchOrdersListWithInfoDict:(NSDictionary*)infoDict completionBlock:(CompletionBlock)completionBlock errorBlock:(ErrorBlock)errorBlock
{
// Using SDMConnectivity
NSString *queryString = [infoDict valueForKey:#"$filter"];
NSString *appendStringForEndpoint = [kRowsetsKeyword stringByAppendingFormat:#"?%#", queryString];
[self fetchDataFromServerWithEndPointAppendString:appendStringForEndpoint
completionBlock:completionBlock
errorBlock:errorBlock];
}
#pragma mark - Service Agent related
-(NSString*)collectionName
{
return [NSString stringWithString:kRowsetsKeyword];
}
-(void)requestFinished:(SDMHttpRequest *)request
{
NSError *error = nil;
// Let's parse the response and send the results back to the caller
NSString *collectionName = [self collectionName];
NSData *responseData = [request responseData];
NSArray *entitiesArray = [self parseODataEntriesWithData:responseData
withCollectionName:collectionName
error:&error];
if (error)
[self triggerFailureBlockWithArgument:error];
else
[self triggerCompletionBlockWithArgument:entitiesArray];
}
#end
Also, HLOrdersDataProvider is inherited from HLDataProvider so below is the interface and implementation of this class too:
#import <Foundation/Foundation.h>
//#import "SDMHttpRequestDelegate.h"
#import "SDMRequestBuilder.h"
#import "SDMHttpRequest.h"
#import "SDMParser.h"
#import "HLConstant.h"
#import "HLConnectionData.h"
#interface HLDataProvider : NSObject <SDMHttpRequestDelegate>
#property (copy, atomic) CompletionBlock completionBlock;
#property (copy , atomic) ErrorBlock errorBlock;
#property (copy, atomic) CompletionBlockWithDataFetchStatus completionBlockWithDataFetchStatus;
+ (id)sharedInstance;
- (NSMutableArray*)parseODataEntriesWithData:(NSData*)data withCollectionName:(NSString*)collectionName;
- (NSMutableArray*)parseODataEntriesWithData:(NSData*)data withCollectionName:(NSString*)collectionName error:(NSError**)outError;
- (NSMutableArray*)parseJSONEntriesWithData:(NSData*)data;
-(NSArray*)fetchEntriesFromDatabaseWithEntityName:(NSString*)entityName relationshipObjects:(NSMutableArray*)relationships;
-(void)updateDatabaseWithEntries:(NSMutableArray*)scanEntries;
-(void)updateDatabaseWithJSONEntries:(NSMutableArray*)scanEntries;
-(id)parsedOdataResultFromEntries:(NSMutableArray*)entries;
-(void)fetchDataFromServerWithEndPointAppendString:(NSString*)appendStr completionBlock:(CompletionBlock)inCompletionBlock errorBlock:(ErrorBlock)inErrorBlock;
-(NSString*)collectionName;
-(void)triggerCompletionBlockWithArgument:(id)inArg;
-(void)triggerFailureBlockWithArgument:(NSError*)inArg;
#end
#implementation HLDataProvider
+ (id)sharedInstance
{
//Subclassess will override this method
return nil;
}
-(NSMutableArray*)parseODataEntriesWithData:(NSData*)data withCollectionName:(NSString*)collectionName
{
return [self parseODataEntriesWithData:data
withCollectionName:collectionName
error:NULL];
}
-(NSMutableArray*)parseODataEntriesWithData:(NSData*)data withCollectionName:(NSString*)collectionName error:(NSError**)outError
{
NSMutableArray *entriesArray = nil;
#try {
entriesArray = sdmParseODataEntriesXML(data,
[[[HLConnectionData metaDataDocument] getCollectionByName:collectionName] getEntitySchema],
[HLConnectionData serviceDocument]);
}
#catch (NSException *exception) {
NSLog(#"Got exception: %#", exception);
if (outError)
{
*outError = [NSError errorWithDomain:#"Vehicle Service"
code:-1001
userInfo:[NSDictionary dictionaryWithObject:exception forKey:NSLocalizedDescriptionKey]];
}
}
#finally {
}
return entriesArray;
}
- (NSMutableArray*)parseJSONEntriesWithData:(NSData*)data
{
NSError *error = nil;
id object = [NSJSONSerialization
JSONObjectWithData:data
options:0
error:&error];
NSMutableArray *resultArray = nil;
if(error) { /* JSON was malformed, act appropriately here */ }
if([object isKindOfClass:[NSDictionary class]])
{
resultArray = [NSMutableArray arrayWithObject:object];
}
else if ([object isKindOfClass:[NSArray class]])
{
resultArray = [NSMutableArray arrayWithArray:object];
}
return resultArray;
}
#pragma mark -
#pragma mark - Data Fetch - Server - SDMConnectivity
-(void)fetchDataFromServerWithEndPointAppendString:(NSString*)appendStr completionBlock:(CompletionBlock)inCompletionBlock errorBlock:(ErrorBlock)inErrorBlock;
{
self.errorBlock = inErrorBlock;
self.completionBlock = inCompletionBlock;
id<SDMRequesting> request = nil;
//NSString *clientStr = #"&sap-client=320&sap-language=EN";
NSString *urlStr =[NSString stringWithFormat:#"%#/%#",[HLConnectionData applicationEndPoint], appendStr];
urlStr = [urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
[SDMRequestBuilder setRequestType:HTTPRequestType];
request=[SDMRequestBuilder requestWithURL:[NSURL URLWithString:urlStr]];
[request setUsername:kUserName];
/*Set Password in SDMRequesting object*/
[request setPassword:kPassword];
[request setRequestMethod:#"GET"];
[request setTimeOutSeconds:kTimeoutInterval];
/*set the Delegate. This class must adhere to SDMHttpRequestDelegate to get the callback*/
[request setDelegate:self];
/*Call startAsynchronous API to request object to retreive Data asynchrnously in the call backs */
[request startSynchronous];
}
-(void)updateDatabaseWithEntries:(NSMutableArray*)scanEntries
{
//Subclasses will override this
}
-(void)updateDatabaseWithJSONEntries:(NSMutableArray*)scanEntries
{
//Subclasses will override this
}
-(id)parsedOdataResultFromEntries:(NSMutableArray*)entries
{
//Subclasses will override this
return nil;
}
-(void)deleteExistingEntriesFromCoredata
{
//Subclasses will override this
}
-(NSArray*)fetchEntriesFromDatabaseWithEntityName:(NSString*)entityName relationshipObjects:(NSMutableArray*)array
{
//Subclasses will overide this method
return nil;
}
#pragma mark - SDMHTTPRequestDelegate methods
- (void)requestStarted:(SDMHttpRequest*) request
{
}
- (void)requestFinished:(SDMHttpRequest*) request
{
// For service doc and metadata we instantiate HLDataProvider, so we send this raw SDMHTTPRequest object as-is. For other service agents like HLOrdersDataProvider we send the parsed information, check the subclass' implementation of -requestFinished: method
[self triggerCompletionBlockWithArgument:request];
}
-(void)triggerCompletionBlockWithArgument:(id)inArg
{
self.completionBlock(inArg);
}
- (void)requestFailed:(SDMHttpRequest*) request
{
[self triggerFailureBlockWithArgument:request.error];
}
-(void)triggerFailureBlockWithArgument:(NSError*)inArg
{
self.errorBlock(inArg);
}
- (void)requestRedirected:(SDMHttpRequest*) request
{
}
#pragma mark - Service Agent related
-(NSString*)collectionName
{
// Should be overridden by the subclasses
return nil;
}
The referenced code is very convoluted (you're doing things in a very complicated way).
First off, you should not be creating the copy of your blocks in the caller. Make the copy in the callee if necessary (ie: to copy it to heap instead of using the stack-allocated block if you are going to call it after the stack has been popped). In almost all APIs using blocks, it is not the caller's responsibility to ensure that a block is on heap.
There is no reason for your ordersDataProvider variable to be declared in the scope of fetchOrdersListTaskBlock because it is only ever used inside of fetchOrdersOperation's block.
I don't immediately see the cause of your crash, but I suspect that simplifying your code will help reveal the problem. Perhaps the issue is in HLOrdersDataProvider's initializer.
Try something like:
-(void)fetchOrdersListWithInfoDict:(NSDictionary*)infoDict completionBlock:(CompletionBlock)completionBlock errorBlock:(ErrorBlock)errorBlock
{
completionBlock = [completionBlock copy];
errorBlock = [errorBlock copy];
__weak VTVehicleServiceNetworkManager *weakSelf = self;
TaskBlock fetchOrdersListTaskBlock = ^{
NSBlockOperation *fetchOrdersOperation = [NSBlockOperation blockOperationWithBlock:^{
HLOrdersDataProvider *ordersDataProvider = [[HLOrdersDataProvider alloc] init];
[ordersDataProvider performFetchOrdersListWithInfoDict:infoDict
completionBlock:completionBlock
errorBlock:errorBlock];
}];
[weakSelf.dataOperationQueue addOperation:fetchOrdersOperation];
};
[self fetchDataWithTaskBlock:fetchOrdersListTaskBlock
errorBlock:errorBlock];
}
Or better yet, re-design your class to work like this (I don't see a need for NSBlockOperation in your example):
-(void)fetchOrdersListWithInfoDict:(NSDictionary*)infoDict completionBlock:(CompletionBlock)completionBlock errorBlock:(ErrorBlock)errorBlock
{
completionBlock = [completionBlock copy];
errorBlock = [errorBlock copy];
TaskBlock fetchOrdersListTaskBlock = ^{
HLOrdersDataProvider *ordersDataProvider = [[HLOrdersDataProvider alloc] init];
[ordersDataProvider performFetchOrdersListWithInfoDict:infoDict
completionBlock:completionBlock
errorBlock:errorBlock];
};
[self fetchDataWithTaskBlock:fetchOrdersListTaskBlock
errorBlock:errorBlock];
}

Coredata unable to delete the existing record + multithreading

I am parsing xml , inserting an entity in the database, for updating record I am again adding that record and deleting the older record. But it is not able to delete the older entry so I am able to see duplicate entries.
- (void)insertSampleWithId:(NSString *)sampleId{
__block NSError *lError = nil;
dispatch_queue_t categoryCustomQueue = dispatch_queue_create("com.xyz.sample”, NULL);
dispatch_sync(categoryCustomQueue, ^{
NSNotificationCenter *dnc = [NSNotificationCenter defaultCenter];
[dnc addObserver:self
selector:#selector(mergeChanges:)
name:NSManagedObjectContextDidSaveNotification
object:_tempMOC];
_supplier = [NSEntityDescription insertNewObjectForEntityForName:#"BSSample” inManagedObjectContext:_tempMOC];
_supplier.sampleId = supplierId;
// double delayInSeconds = 0.3;
// dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
//
// dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
//
// });
[self ifSupplierPresentInMainContextRemoveIt:supplierId];
if(![_tempMOC save:&lError]){
NSLog(#"Error adding while category %# ,%# ,%#", lError, [lError userInfo], [lError localizedDescription]);
}
[dnc removeObserver:self name:NSManagedObjectContextDidSaveNotification object:_tempMOC];
});
}
- (BOOL)ifSamplePresentInMainContextRemoveIt:(NSString *)sampleId{
__block BSSampler *suppl = nil;
NSManagedObjectContext *managedObjectContext = dataManager.coreDataHelper.context;
NSEntityDescription *entityDescription = [NSEntityDescription
entityForName:#"BSSample” inManagedObjectContext:managedObjectContext];
[_fetchRequest setEntity:entityDescription];
[_fetchRequest setPredicate:[NSPredicate predicateWithFormat:#"sampleId == '%#'", supplierId]];
[_fetchRequest setResultType:NSDictionaryResultType];
[_fetchRequest setReturnsDistinctResults:YES];
NSError *error;
NSArray *array = [managedObjectContext executeFetchRequest:_fetchRequest error:&error];
if(array != nil && [array count]>0){
suppl = [array objectAtIndex:0];
}
if(suppl)
[dataManager.coreDataHelper.context deleteObject:suppl];
return [dataManager.coreDataHelper.context save:&error];
}
- (void)mergeChanges:(NSNotification *)saveNotification{
[self performSelectorOnMainThread:#selector(mergeToMainThred:) withObject:saveNotification waitUntilDone:NO];
}
- (void)mergeToMainThred:(NSNotification*)saveNotification{
[dataManager.coreDataHelper.context mergeChangesFromContextDidSaveNotification:saveNotification];
}
There is no code here that shows your delete.
You say that are not able to delete but you don't say why or how. What is failing? What is your expectation and what is the actual results?
What does mergeChanges: look like?
Please update your question so that we have a chance of understanding the issue.

How can i get latest new mail using Mailcore2 Api?

I am new bie in IOS developement.I am stuck in this problem
I am using Mailcore2 api in my ios app.I want to get the new emails which are recently coming in Inbox.
Here is my Code
In ViewDidLoad method..
-(void)viewDidLoad
{
[super viewDidLoad];
NSUserDefaults *defaules = [NSUserDefaults standardUserDefaults];
NSString *emailid = [defaules objectForKey:#"emailid" ];
NSString *password = [defaules objectForKey:#"password" ];
session = [[MCOIMAPSession alloc] init];
session.hostname = #"imap.gmail.com";
session.port = 993;
session.username = emailid;
session.password = password;
session.connectionType = MCOConnectionTypeTLS;
MCOIMAPIdleOperation *idle=[session idleOperationWithFolder:#"INBOX" lastKnownUID:64];
[idle start:^(NSError *error)
{
NSLog(#"finished checking account.");
if (error) {
NSLog(#"ERROR-%#",error);
}
else
{
NSLog(#"DONE");
[self fetchemail:10 folder:#"INBOX"];
}
}];
double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
[idle interruptIdle];
NSLog(#"HELOO");
});
}
by this method all the emails are loaded when the view is load.
I have use MCOIMAPIdleoperation to get latest emails but it is not working.
but latest email is not fetched.
Please Help to get over it..

serial asynchronous calls for each item in an array

given an array of objects, I would like to make an asynchronous call for each object, and then not proceed to the next object until the asynchronous call for the previous object completes.
I have this working code:
#import <XCTest/XCTest.h>
#import <ReactiveCocoa/ReactiveCocoa.h>
#import <TRVSMonitor/TRVSMonitor.h>
#interface FSReactiveCocoaArraySignalProcessingTests : XCTestCase{
NSArray *sequence;
}
#end
#implementation FSReactiveCocoaArraySignalProcessingTests
-(void)setUp{
[super setUp];
sequence = #[#"dog", #"cat", #"mouse", #"rabbit", #"wallabee"];
}
-(void)tearDown{
[super tearDown];
}
- (void)test_maybe_using_the_disposable_method_of_creating_a_signal{
TRVSMonitor *monitor = [TRVSMonitor monitor];
RACSignal *resultingSignal = [[sequence.rac_sequence
map:^(NSString *val){
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
NSLog(#"returning signal for %#", val);
[[self fakeApiCall:val]
subscribeNext:^(id next){
[subscriber sendNext:next];
}
completed:^{
[subscriber sendCompleted];
}];
return nil;
}];
}]
foldLeftWithStart:[RACSignal empty]
reduce:^RACSignal *(RACSignal *left, RACSignal *right){
return [left
then:^{
return [right doNext:^(RACTuple *tuple){
//real world side effect for processing end of call.
RACTupleUnpack(NSString *val, NSNumber *len) = tuple;
NSLog(#"word %# has %# chars", val, len);
}];
}];
}];
[resultingSignal subscribeCompleted:^{
NSLog(#"FIN!");
[monitor signal];
}];
XCTAssertTrue([monitor waitWithTimeout:10]);
}
//Returns a new signal that returns a RACTuple<NSString *, NSNumber *>
-(RACSignal *)fakeApiCall:(NSString *)val{
return [[RACSignal return:RACTuplePack(val, #(val.length))]
delay:.5];
}
#end
https://gist.github.com/jonnolen/b0e071b8dd202f7ed912
The question: is there a "more reactive" way to accomplish this?

Block passing itself as argument to method causing compiler warning

I was trying to create a callback that retries the method after a delay on failure. I'm hitting this warning:
"Capturing failure block strongly in this block is likely to lead to a retain cycle."
typedef void (^MyCallbackBlock)(NSObject *);
...
__block MyObject *blockSelf = self;
__block MyCallbackBlock successBlock = ^(NSObject *someObject)
{
// To be completed
};
__block MyCallbackBlock failureBlock = ^(NSObject *someObject)
{
double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
[blockSelf doSomething:someObject onSuccess:successBlock onFailure:failureBlock]; // <-- Warning is here
});
};
[blockSelf doSomething:someObject onSuccess:successBlock onFailure:failureBlock];
...
- (void)doSomething:(NSObject *)someObject
onSuccess:(MyCallbackBlock)successBlock
onFailure:(MyCallbackBlock)failureBlock;
The question: How can I make this work properly?
(I've been reading through other SO questions -- haven't found a match yet, though wouldn't be surprised if one is out there.)
Yes, the block needs to capture itself (as well as self) as a weak reference.
If you're using ARC*, it should be like this:
MyObject *__weak blockSelf = self;
__block __weak MyCallbackBlock weakSuccessBlock;
MyCallbackBlock successBlock = weakSuccessBlock = ^(NSObject *someObject)
{
// To be completed
};
__block __weak MyCallbackBlock weakFailureBlock;
MyCallbackBlock failureBlock = weakFailureBlock = ^(NSObject *someObject)
{
MyCallbackBlock strongSuccessBlock = weakSuccessBlock;
MyCallbackBlock strongFailureBlock = weakFailureBlock;
double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
[blockSelf doSomething:someObject onSuccess:strongSuccessBlock onFailure:strongFailureBlock];
});
};
If you're not using ARC, replace the __block __weak and __weak above with just __block.
*: Objective-C Automatic Reference Counting
Adding __unsafe_unretained worked, as in:
__unsafe_unretained __block MyCallbackBlock successBlock = ^(NSObject *someObject)
{
// To be completed
};
While it seemed possible that __weak could work, in practice it caused my application to crash. It's not 100% clear that this answer explains the reason, but I'm imagining it's something along those lines.