I have following code in Objective C that fetches events from calendar. Its working code.
I migrated to Swift but fail to write the same in Swift language.
NSMutableArray *events = [[NSMutableArray alloc]init];
[_eventStore enumerateEventsMatchingPredicate:predicate
usingBlock:^(EKEvent *event, BOOL *stop) {
if (event)
{
NSUInteger fid = [events indexOfObjectPassingTest:^(id obj, NSUInteger idx, BOOL *stop)
{
EKEvent *revent = (EKEvent*)obj;
if (sameAttendees(event.attendees, revent.attendees)) // my method
{
*stop = YES;
return YES;
}
return NO;
}];
}
}];
The issue is that syntax is changed to:
_eventStore.enumerateEventsMatchingPredicate(predicate, usingBlock: EKEventSearchCallback!)
How to write EKEventSearchCallback in Swift?
From docs:
typedef void (^EKEventSearchCallback)(EKEvent *event, BOOL *stop);
please help,
This is how its works:
_eventStore.enumerateEventsMatchingPredicate(predicate, usingBlock:{
(event:EKEvent!, stop:UnsafeMutablePointer<ObjCBool>) in
// inner code
}) // block
Related
I got some problems with my codes that i can't tell.
Will u finger it out for me?
And can you help answer some of the following questions?
This class's functions may be called in multi-thread situation.
#import "FileHandler.h"
#import <pthread.h>
#define kJsonFilePath [NSTemporaryDirectory() stringByAppendingString:#"/foo/jsonFile.json"]
static pthread_mutex_t _lock;
#implementation FileHandler
+ (void)initialize
{
if (self == [YWMultiAccountsHandle class]) {
pthread_mutex_init(&_lock, NULL);
}
}
+ (void)writeIntoTheFileWithArray:(NSArray *)arr
{
pthread_mutex_lock(&_lock);
NSMutableArray *muArr = [NSMutableArray array];
[arr enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if (![obj isKindOfClass:[NSDictionary class]]) {
[muArr addObject:[obj get_keyValues]];
}
else
{
[muArr addObject:obj];
}
}];
pthread_mutex_unlock(&_lock);
NSData *data = [NSJSONSerialization dataWithJSONObject:[muArr copy] options:NSJSONWritingPrettyPrinted error:nil];
pthread_mutex_lock(&_lock);
[data writeToFile:kJsonFilePath atomically:YES];
pthread_mutex_unlock(&_lock);
}
1.Can i remove the pthread_mutex_unlock(&_lock); and pthread_mutex_lock(&_lock); in the middle?
2.Is there any problem in this class?
3.when the _lock will release and dealloc?
4.Is it thread safe?
I am making an app where I want to get the list of all albums name from gallery including smart folders(favorites, screenshots. this is an old app where we have used ALAsset in order to access the gallery in our app.
Is there any way through which we can access smart folders as well using ALAssetLibrary?
This code is help.
#import <AssetsLibrary/AssetsLibrary.h>
#property (nonatomic, strong) ALAssetsLibrary *_assetsLibrary;
- (ALAssetsLibrary *)defaultAssetsLibrary {
static dispatch_once_t pred = 0;
static ALAssetsLibrary *library = nil;
dispatch_once(&pred, ^{
library = [[ALAssetsLibrary alloc] init];
});
return library;
}
-(void) getgalleryPic
{
if (self.photos == nil) {
self.photos = [[NSMutableArray alloc] init];
}else
{
[self.photos removeAllObjects];
}
PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus];
if (status == PHAuthorizationStatusAuthorized) {
// Access has been granted.
NSMutableArray *collector = [[NSMutableArray alloc] initWithCapacity:0];
ALAssetsLibrary *library = [self defaultAssetsLibrary];
[library enumerateGroupsWithTypes:ALAssetsGroupAll
usingBlock:^(ALAssetsGroup *group, BOOL *stop)
{
[group enumerateAssetsUsingBlock:^(ALAsset *asset, NSUInteger index, BOOL *stop)
{
if (asset) {
[collector addObject:asset];
}else
{
self.photos = [[[collector reverseObjectEnumerator] allObjects] mutableCopy];
NSLog(#"photo lenght %lu",(unsigned long)[self.photos count]);
[_collectionVW reloadData];
}
}];
}
failureBlock:^(NSError *error) { NSLog(#"Boom!!!");}
];
}
else if (status == PHAuthorizationStatusDenied) {
// Access has been denied.
}
else if (status == PHAuthorizationStatusNotDetermined) {
// Access has not been determined.
[PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
if (status == PHAuthorizationStatusAuthorized) {
// Access has been granted.
NSMutableArray *collector = [[NSMutableArray alloc] initWithCapacity:0];
ALAssetsLibrary *library = [self defaultAssetsLibrary];
[library enumerateGroupsWithTypes:ALAssetsGroupAll
usingBlock:^(ALAssetsGroup *group, BOOL *stop)
{
[group enumerateAssetsUsingBlock:^(ALAsset *asset, NSUInteger index, BOOL *stop)
{
if (asset) {
[collector addObject:asset];
}else
{
self.photos = [[[collector reverseObjectEnumerator] allObjects] mutableCopy];
NSLog(#"photo lenght %lu",(unsigned long)[self.photos count]);
[_collectionVW reloadData];
}
}];
}
failureBlock:^(NSError *error) { NSLog(#"Boom!!!");}
];
}
else {
// Access has been denied.
}
}];
} else if (status == PHAuthorizationStatusRestricted) {
// Restricted access - normally won't happen.
}
}
The documentation on NSSet objectEnumeration says:
When this method is used with mutable subclasses of NSSet, your code shouldn’t modify the set during enumeration. If you intend to modify the set, use the allObjects method to create a “snapshot” of the set’s members. Enumerate the snapshot, but make your modifications to the original set.
Now my question is: Is the allObjects method itself thread safe?
I have implemented an operation set like so:
#interface OperationSet : NSObject
#end
#implementation OperationSet
{
NSMutableSet *_set;
}
- (instancetype)init
{
self = [super init];
if (self)
{
_set = [[NSMutableSet alloc] init];
}
return self;
}
- (void)addOperation:(Operation *)operation
{
if (operation)
{
[_set addObject:operation];
}
}
- (void)removeOperation:(Operation *)operation
{
if (operation)
{
[_set removeObject:operation];
}
}
- (void)removeAllOperations
{
[_set removeAllObjects];
}
- (void)enumerateWithOperationBlock:(OperationBlock)block
{
NSArray *allObjects = [_set allObjects];
[allObjects enumerateObjectsUsingBlock:^(Operation *o, NSUInteger idx, BOOL *stop) {
block(o);
}];
}
- (void)flushCompletedOperations
{
NSArray *allObjects = [_set allObjects];
NSSet *safeSet = [NSSet setWithArray:allObjects];
NSSet *completed = [safeSet objectsPassingTest:^BOOL(Operation *o, BOOL *stop){
return o.completed;
}];
[_set minusSet:completed];
}
- (NSUInteger)count
{
return [_set count];
}
- (BOOL)any:(OperationAnyBlock)block
{
NSArray *allObjects = [_set allObjects];
NSUInteger index = [allObjects indexOfObjectPassingTest:^BOOL(Operation *o, NSUInteger idx, BOOL *stop) {
return block(o);
}];
return (index != NSNotFound);
}
- (Operation *)getOperationWithMatchingData:(NSDictionary *)data
{
NSArray *allObjects = [_set allObjects];
NSUInteger index = [allObjects indexOfObjectPassingTest:^BOOL(Operation *o, NSUInteger idx, BOOL *stop) {
return [o matchesData:data];
}];
return (index == NSNotFound ? nil : allObjects[index]);
}
#end
This all works fine.
But I have got a crash via Crashlytics, which is rare (two out of hundreds), but is there:
EXC_BAD_ACCESS KERN_INVALID_ADDRESS at 0x0000000000000008
Thread : Crashed: com.apple.main-thread
0 CoreFoundation 0x000000018772c438 -[__NSSetM addObject:] + 448
1 CoreFoundation 0x000000018772c430 -[__NSSetM addObject:] + 440
The OperationSet is accessed from multiple threads.
Any help is greatly appreciated.
EDIT
Thanks dasblinkenlight for enlighting the allObjects usage.
I have edited my implementation like so:
#interface OperationSet : NSObject
#end
#implementation OperationSet
{
NSMutableSet *_set;
dispatch_queue_t _queue;
}
- (instancetype)init
{
self = [super init];
if (self)
{
_set = [[NSMutableSet alloc] init];
_queue = dispatch_queue_create("OperationQueue", DISPATCH_QUEUE_SERIAL);
}
return self;
}
- (void)addOperation:(Operation *)operation
{
if (operation)
{
dispatch_async(_queue, ^{
[_set addObject:operation];
});
}
}
- (void)removeOperation:(Operation *)operation
{
if (operation)
{
dispatch_async(_queue, ^{
[_set removeObject:operation];
});
}
}
- (void)removeAllOperations
{
dispatch_async(_queue, ^{
[_set removeAllObjects];
});
}
- (void)enumerateWithOperationBlock:(OperationBlock)block
{
__block NSArray *allObjects;
dispatch_sync(_queue, ^{
allObjects = [_set allObjects];
});
[allObjects enumerateObjectsUsingBlock:^(Operation *o, NSUInteger idx, BOOL *stop) {
block(o);
}];
}
- (void)flushCompletedOperations
{
__block NSArray *allObjects;
dispatch_sync(_queue, ^{
allObjects = [_set allObjects];
});
NSSet *safeSet = [NSSet setWithArray:allObjects];
NSSet *completed = [safeSet objectsPassingTest:^BOOL(Operation *o, BOOL *stop){
return o.completed;
}];
[_set minusSet:completed];
}
- (NSUInteger)count
{
return [_set count];
}
- (BOOL)any:(OperationAnyBlock)block
{
__block NSArray *allObjects;
dispatch_sync(_queue, ^{
allObjects = [_set allObjects];
});
NSUInteger index = [allObjects indexOfObjectPassingTest:^BOOL(Operation *o, NSUInteger idx, BOOL *stop) {
return block(o);
}];
return (index != NSNotFound);
}
- (Operation *)getOperationWithMatchingData:(NSDictionary *)data
{
__block NSArray *allObjects;
dispatch_sync(_queue, ^{
allObjects = [_set allObjects];
});
NSUInteger index = [allObjects indexOfObjectPassingTest:^BOOL(Operation *o, NSUInteger idx, BOOL *stop) {
return [o matchesData:data];
}];
return (index == NSNotFound ? nil : allObjects[index]);
}
#end
The code works! Which is a good sign, but can you please review it?
And there is another question: Is there any difference in using allObjects versus making a set copy?
That is using this code:
- (void)enumerateWithOperationBlock:(OperationBlock)block
{
__block NSArray *allObjects;
dispatch_sync(_queue, ^{
allObjects = [_set allObjects];
});
[allObjects enumerateObjectsUsingBlock:^(Operation *o, NSUInteger idx, BOOL *stop) {
block(o);
}];
}
over this code:
- (void)enumerateWithOperationBlock:(OperationBlock)block
{
__block NSSet *safeSet;
dispatch_sync(_queue, ^{
safeSet = [_set copy];
});
[safeSet enumerateObjectsUsingBlock:^(Operation *o, BOOL *stop) {
block(o);
}];
}
Thanks for your help.
NSMutableSet is not thread-safe. If you wish to access one from multiple threads, you must enforce one-at-a-time access yourself.
This is documented in “Thread Safety Summary” in the Threading Programming Guide.
The typical way to enforce one-at-a-time access is by creating one GCD queue (for each set) and accessing the set only from that queue (using dispatch_sync or, if possible, dispatch_async). In your example, you would add a dispatch_queue_t instance variable to your class, initialize it ininit, and use it in each of your other instance methods.
NSMutableSet is listed among the classes that are not thread-safe, so its methods should be considered non-thread safe unless explicitly documented otherwise (none of the NSMutableSet methods are documented as thread-safe at this time).
I think that by
use the allObjects method to create a “snapshot”
they meant creating a snapshot behind a lock, to avoid holding a lock on the entire set during the entire time that it takes you to enumerate its objects, and perform operations on them.
Your other question: [mySet allObjects] returns an NSArray containing all the objects in the set, while [mySet copy] returns an NSSet. If you don't need the properties of a set (very fast test for membership), an NSArray will probably be a bit quicker.
here is my code:
[library enumerateGroupsWithTypes:ALAssetsGroupAlbum
usingBlock:assetGroupEnumerator
failureBlock: ^(NSError *error) {
NSLog(#"Failure");
}];
my previous code is this:
assets = [[NSMutableArray alloc] init];
void (^assetEnumerator)( ALAsset *, NSUInteger, BOOL *) = ^(ALAsset *result, NSUInteger index, BOOL *stop) {
if(result != NULL) {
NSLog(#"See Asset: %#", result);
[assets addObject:result];
}
};
void (^assetGroupEnumerator)( ALAssetsGroup *, BOOL *) = ^(ALAssetsGroup *group, BOOL *stop) {
if(group != nil) {
[group enumerateAssetsUsingBlock:assetEnumerator];
}
[self.tableView reloadData];
};
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
and with my phone (ios5) doesn't work, can't go to the assetGroupEnumerator...
also in the simulator, the same thing....
any ideas?
thanks in advance
Are you releasing your ALAssetsLibrary before you are done displaying the assets? You need to retain the library throughout the lifetime of the groups and assets you are using.
For example I would see the following:
- (void) updateNotesView:(BOOL)visible animated:(BOOL)animated{
void (^animations)(void) = ^{
if (visible)
{
//do something
}
else
{
//do something
}
};
void (^completion)(BOOL) = ^(BOOL finished){
self.showingNotesView = visible;
if (!visible)
{
//do something
}
};
}
I do not get the code that says :
void (^animations)(void)
or
void (^completion)(BOOL) = ^(BOOL finished)
can someone please explain?
It's how you define a variable that will be a block or in some other cases function pointers like in c.
int (*pt2Function)(float, char, char) = NULL;
if (pt2Function)
pt2Function(5.0f, 'a', 'b');
NSArray* array = [NSArray arrayWithObjects:#"a",#"b", nil];
void(^enumerateBlock)(id,NSUInteger,BOOL*) = ^(id obj, NSUInteger idx, BOOL *stop) {
// some code
};
[array enumerateObjectsUsingBlock:enumerateBlock];
// OR
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
// inline block
}];
// using a typedef for code neatness
typedef void(^typedefBlockVar)(id,NSUInteger,BOOL*);
typedefBlockVar myEnumrateBlock = ^(id obj, NSUInteger idx, BOOL *stop) {
// some code
};
[array enumerateObjectsUsingBlock:myEnumrateBlock];