Objective C to Swift dispatch process - objective-c

i'm having some trouble trying to convert the following code in Objective C to Swift:
- (BOOL)loadEventsAtDate:(NSDate*)date
{
dispatch_async(self.bgQueue, ^{
[self bg_loadOneDay];
});
return YES;
}
- (void)bg_loadOneDay
{
__block NSDate *date;
dispatch_sync(dispatch_get_main_queue(), ^{
.....
});
if (date) {
[self bg_loadEventsAtDate:date];
}
}
- (void)bg_loadEventsAtDate:(NSDate*)date
{
dispatch_async(dispatch_get_main_queue(), ^{
......
});
}
Can you please help me?I' m quite new to this!!!Thank you in advance!!!

Try this:
func loadEventsAtDate(date: NSDate) -> Bool {
let bgQueue = dispatch_queue_create("MY_BG_QUEUE", DISPATCH_QUEUE_SERIAL)//use your `bgQueue`
dispatch_async(bgQueue) {
self.bg_loadOneDay()
}
return true
}
func bg_loadOneDay() {
let date = NSDate()
dispatch_async(dispatch_get_main_queue()) {
//....
}
bg_loadEventsAtDate(date)//not sure which date you are sending here, please check
}
func bg_loadEventsAtDate(date: NSDate) {
dispatch_async(dispatch_get_main_queue()) {
//....
}
}

Related

Annotations not loading properly

Im trying to load my annotations using JPSThumbnail on swift. With the code below for some reason whenever It loads, it loads my annotations with the usual red pin. I have no clue in objective C so I dont know what should be done? What is missing in my code, am I appending right to the array?
JPSThumnail Github
JPSThumbnailAnnotation:
+ (instancetype)annotationWithThumbnail:(JPSThumbnail *)thumbnail {
return [[self alloc] initWithThumbnail:thumbnail];
}
- (id)initWithThumbnail:(JPSThumbnail *)thumbnail {
self = [super init];
if (self) {
_coordinate = thumbnail.coordinate;
_thumbnail = thumbnail;
}
return self;
}
- (MKAnnotationView *)annotationViewInMap:(MKMapView *)mapView {
if (!self.view) {
self.view = (JPSThumbnailAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:kJPSThumbnailAnnotationViewReuseID];
if (!self.view) self.view = [[JPSThumbnailAnnotationView alloc] initWithAnnotation:self];
} else {
self.view.annotation = self;
}
[self updateThumbnail:self.thumbnail animated:NO];
return self.view;
}
- (void)updateThumbnail:(JPSThumbnail *)thumbnail animated:(BOOL)animated {
if (animated) {
[UIView animateWithDuration:0.33f animations:^{
_coordinate = thumbnail.coordinate; // use ivar to avoid triggering setter
}];
} else {
_coordinate = thumbnail.coordinate; // use ivar to avoid triggering setter
}
[self.view updateWithThumbnail:thumbnail];
}
My Swift Code:
func annotations() -> [JPSThumbnailAnnotation] {
var annotations: [JPSThumbnailAnnotation] = []
let pointData = NSData(contentsOfFile: NSBundle.mainBundle().pathForResource("1000", ofType: "geojson")!)
let points = NSJSONSerialization.JSONObjectWithData(pointData!,
options: nil,
error: nil) as! NSDictionary
for point in points["glimps"] as! NSArray {
var a = JPSThumbnail()
a.image = UIImage(named: "empire.jpg")
a.title = "Empire State Building"
a.subtitle = "NYC Landmark"
var lat = (point as! NSDictionary)["latitude"] as! CLLocationDegrees
var lon = (point as! NSDictionary)["longitude"] as! CLLocationDegrees
a.coordinate = CLLocationCoordinate2DMake(lat, lon)
a.disclosureBlock = { println("selected Empire") }
var a1: JPSThumbnailAnnotation = JPSThumbnailAnnotation(thumbnail: a)
annotations.append(a1)
}
return annotations
}
func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! {
return (annotation as? JPSThumbnailAnnotationProtocol)?.annotationViewInMap(mapView)
}

Objective-c block synchronizing data

I'm developing a program that gets feed from Instagram. I'm really new to objective-c so please be patient with my question. I have a button that calls a method to get the feeds, but it is a block so when the method finishes sometimes the block still continues loading images. The problem occurs when I change the user. I clear the media array but the method fired fills the array with old user data. I tried to use a property userchanged but it seems that it cancels the current user data too. How should I synchronize these methods? I can't figure it out.
#property (nonatomic, copy) NSMutableArray *mediaArray;
#property (nonatomic, assign) BOOL currentUserChanged;
- (void)getInstagramSelfFeed
{
if (self.currentPaginationInfo.nextMaxId != self.requestedPaginationInfo)
{
self.requestedPaginationInfo = self.currentPaginationInfo.nextMaxId;
[[InstagramEngine sharedEngine] getSelfFeedWithCount:15 maxId:self.currentPaginationInfo.nextMaxId success:^(NSArray *media, InstagramPaginationInfo *paginationInfo){
self.currentPaginationInfo = paginationInfo;
if ([self checkIfCurrentUserChanged])
{
return;
}
[self.mediaArray addObjectsFromArray:media];
[[NSNotificationCenter defaultCenter] postNotificationName:#"finishGettingSelfFeed" object:self];
} failure:^(NSError *error) {
NSLog(#"Request Self Feed Failed %#", error);
}];
}
}
- (void)setCurrentUser:(User *)currentUser
{
if (_currentUser != currentUser)
{
_currentUser = currentUser;
[[InstagramEngine sharedEngine] setAccessToken:self.currentUser.accessToken];
[self.mediaArray removeAllObjects];
if ([self.currentViewController isKindOfClass:[TimelineViewController class]])
{
self.currentUserChanged = YES;
}
MenuController *menuController = [MenuController sharedManager];
[menuController updateAllViews];
}
}
- (User *)currentUser
{
return _currentUser;
}
- (BOOL)checkIfCurrentUserChanged
{
if (self.currentUserChanged)
{
self.currentUserChanged = false;
return YES;
}
return NO;
}
OK, I solved the problem. Now I'm sending the user that made the request and compare both.
- (void)getInstagramSelfFeed: (User *)user
{
if (self.currentPaginationInfo.nextMaxId != self.requestedPaginationInfo)
{
self.requestedPaginationInfo = self.currentPaginationInfo.nextMaxId;
self.executingGetSelfFeed = true;
[[InstagramEngine sharedEngine] getSelfFeedWithCount:15 maxId:self.currentPaginationInfo.nextMaxId success:^(NSArray *media, InstagramPaginationInfo *paginationInfo){
self.currentPaginationInfo = paginationInfo;
if (user != self.currentUser)
{
[[NSNotificationCenter defaultCenter] postNotificationName:#"gettingSelfFeedCancelled" object:self];
return;
}
[self.mediaArray addObjectsFromArray:media];
[[NSNotificationCenter defaultCenter] postNotificationName:#"finishGettingSelfFeed" object:self];
} failure:^(NSError *error) {
NSLog(#"Request Self Feed Failed %#", error);
}];
}
}
A big problem is that you have a mutable array, and it is a "copy" property. That's just wrong. When you access self.mediaArray, a copy of the instance variable is made, and then you modify the copy. The instance variable itself is never modified.

Block does not react to outside property change

After some questions here I decided to run a server like this:
#implementation Server
-(id)init
{
if (self = [super init])
{
shouldRun = true;
__block Server* blocksafeSelf = self; // should prevent retain cycle
myServer = ^() {
dispatch_async(dispatch_get_main_queue(), ^{
NSString* currentText = controller.output.text;
controller.outputTextField.text = [currentText stringByAppendingString:#"Server ready. \n"];
});
while (blocksafeSelf.shouldRun) {
int bytes_received = recvfrom(...);
if (bytes_received > 0) {
switch (TYPE OF RECEIVED PACKET) {
case 1: {
dispatch_async(dispatch_get_main_queue(), ^{
NSString* currentText = controller.outputTextField.text;
controller.outputTextField.text = [currentText stringByAppendingString:#"S: Received Typ 1 "];
});
[blocksafeSelf methodToDealWithPacket:(PACKETTYPE*) buffer];
break;
}
...
default: {
...
}
}
}
}
return self;
}
#synthesize shouldRun;
the corresponding .h file:
#interface Server : NSObject {
ServerBlock myServer;
....
}
#property BOOL shouldRun;
....
#end
Now I have a ViewController, which has the Server as a property and following method in its implementation:
// called when the user clicks the stop button
- (IBAction) clickedStop
{
if(theServer != nil) {
theServer.shouldRun = false;
}
}
When I click the stop button however, the server does not exit his while loop. Why?
edit: Here is, how the server is started in the ViewController:
// called when the user clicks the start button
- (IBAction) clickedStart
{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
if (...) { // all needed data has been entered
// start server here
if(theServer == nil) {
theServer = [[SNPTServer alloc] initWithHost:serverIP.text AndPort: [serverPort.text intValue] AndViewController:self];
dispatch_async(queue, theServer.myServer);
}
}
}
As you see, I have altered the constructor above a bit.
My answer will only work if the body of your while loop looks similar to the following (I will assume it does)
while (blocksafeSelf.shouldRun) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
beforeDate:[NSDate distantFuture]];
}
In this case, just setting shouldRun to NO is not enough. That while loop is running on a different thread/runLoop so an event must happen to cause the run loop to pop so that the condition is checked again.
The easiest way to do that is to set shouldRun to NO from the thread that server is running on. I would do something like this:
myServer = ^() {
self.runThread = [NSThread currentThread]; // runThread declared elsewhere
while (blocksafeSelf.shouldRun) {
....
}
}
And then when you want to cancel it do:
- (IBAction) clickedStop
{
if ([NSThread currentThread] == theServer.runThread) {
if(theServer != nil) {
theServer.shouldRun = NO;
}
} else if (theServer.runThread) {
[self performSelector:_cmd
onThread:theServer.runThread
withObject:nil
waitUntilDone:NO];
}
}

Singleton method not getting called in Cocos2d

I am calling a Singleton method that does not get called when I try doing this.
I get no errors or anything, just that I am unable to see the CCLOG message.
Under what reasons would a compiler not give you error and not allow you to call a method?
[[GameManager sharedGameManager] openSiteWithLinkType:kLinkTypeDeveloperSite];
The method is defined as follows:
-(void)openSiteWithLinkType:(LinkTypes)linkTypeToOpen
{
CCLOG(#"WE ARE IN openSiteWithLinkType"); //I NEVER SEE THIS MESSAGE
NSURL *urlToOpen = nil;
if (linkTypeToOpen == kLinkTypeDeveloperSite)
{
urlToOpen = [NSURL URLWithString:#"http://somesite.com"];
}
if (![[UIApplication sharedApplication]openURL:urlToOpen])
{
CCLOG(#"%#%#",#"Failed to open url:",[urlToOpen description]);
[self runSceneWithID:kMainMenuScene];
}
}
HERE IS THE CODE TO MY SINGLETON:
#import "GameManager.h"
#import "MainMenuScene.h"
#implementation GameManager
static GameManager* _sharedGameManager = nil;
#synthesize isMusicON;
#synthesize isSoundEffectsON;
#synthesize hasPlayerDied;
+(GameManager*) sharedGameManager
{
#synchronized([GameManager class])
{
if (!_sharedGameManager)
{
[[self alloc] init];
return _sharedGameManager;
}
return nil;
}
}
+(id)alloc
{
#synchronized ([GameManager class])
{
NSAssert(_sharedGameManager == nil,#"Attempted to allocate a second instance of the Game Manager singleton");
_sharedGameManager = [super alloc];
return _sharedGameManager;
}
return nil;
}
-(id)init
{
self = [super init];
if (self != nil)
{
//Game Manager initialized
CCLOG(#"Game Manager Singleton, init");
isMusicON = YES;
isSoundEffectsON = YES;
hasPlayerDied = NO;
currentScene = kNoSceneUninitialized;
}
return self;
}
-(void) runSceneWithID:(SceneTypes)sceneID
{
SceneTypes oldScene = currentScene;
currentScene = sceneID;
id sceneToRun = nil;
switch (sceneID)
{
case kMainMenuScene:
sceneToRun = [MainMenuScene node];
break;
default:
CCLOG(#"Unknown Scene ID, cannot switch scenes");
return;
break;
}
if (sceneToRun == nil)
{
//Revert back, since no new scene was found
currentScene = oldScene;
return;
}
//Menu Scenes have a value of < 100
if (sceneID < 100)
{
if (UI_USER_INTERFACE_IDIOM() != UIUserInterfaceIdiomPad)
{
CGSize screenSize = [CCDirector sharedDirector].winSizeInPixels;
if (screenSize.width == 960.0f)
{
//iPhone 4 retina
[sceneToRun setScaleX:0.9375f];
[sceneToRun setScaleY:0.8333f];
CCLOG(#"GM: Scaling for iPhone 4 (retina)");
}
else
{
[sceneToRun setScaleX:0.4688f];
[sceneToRun setScaleY:0.4166f];
CCLOG(#"GM: Scaling for iPhone 3G or older (non-retina)");
}
}
}
if ([[CCDirector sharedDirector] runningScene] == nil)
{
[[CCDirector sharedDirector] runWithScene:sceneToRun];
}
else
{
[[CCDirector sharedDirector] replaceScene:sceneToRun];
}
}
-(void)openSiteWithLinkType:(LinkTypes)linkTypeToOpen
{
CCLOG(#"WE ARE IN openSiteWithLinkType");
NSURL *urlToOpen = nil;
if (linkTypeToOpen == kLinkTypeDeveloperSite)
{
urlToOpen = [NSURL URLWithString:#"http://somesite.com"];
}
if (![[UIApplication sharedApplication]openURL:urlToOpen])
{
CCLOG(#"%#%#",#"Failed to open url:",[urlToOpen description]);
[self runSceneWithID:kMainMenuScene];
}
}
-(void) test
{
CCLOG(#"this is test");
}
#end
Perhaps sharedGameManager is returning nil? This won't cause an error.
Edit: The issue is in the new code you posted:
if (!_sharedGameManager) {
[[self alloc] init];
return _sharedGameManager;
}
return nil;
If _sharedGameManager is non-nil, this will return nil. You want:
if (!_sharedGameManager) {
[[self alloc] init];
}
return _sharedGameManager;
Check this Cocoa With Love article on how to make a proper singleton.

NSOutlineView example

Please, could you give a simple complete example of Cocoa application with NSOutlineView with hierarchical data representation not so ambiguous like NSOutlineView and NSTreeController example
.
Thanks!
This example uses a simple two layer hierarchy of two parents Foo and Bar who each have two kids, Foox, Fooz and Barx, Barz respectively, the outline view is the default one with just two columns and the identifier of the second column is set to "children".
NSDictionary *firstParent = #{#"parent": #"Foo", #"children": #[#"Foox", #"Fooz"]};
NSDictionary *secondParent = #{#"parent": #"Bar", #"children": #[#"Barx", #"Barz"]};
NSArray *list = #[firstParent, secondParent];
- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item
{
if ([item isKindOfClass:[NSDictionary class]]) {
return YES;
}else {
return NO;
}
}
- (NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item
{
if (item == nil) { //item is nil when the outline view wants to inquire for root level items
return [list count];
}
if ([item isKindOfClass:[NSDictionary class]]) {
return [[item objectForKey:#"children"] count];
}
return 0;
}
- (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item
{
if (item == nil) { //item is nil when the outline view wants to inquire for root level items
return [list objectAtIndex:index];
}
if ([item isKindOfClass:[NSDictionary class]]) {
return [[item objectForKey:#"children"] objectAtIndex:index];
}
return nil;
}
- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)theColumn byItem:(id)item
{
if ([[theColumn identifier] isEqualToString:#"children"]) {
if ([item isKindOfClass:[NSDictionary class]]) {
return [NSString stringWithFormat:#"%i kids",[[item objectForKey:#"children"] count]];
}
return item;
}else{
if ([item isKindOfClass:[NSDictionary class]]) {
return [item objectForKey:#"parent"];
}
}
return nil;
}
NSOutlineView using NSURL and Swift simple example populating directory structure
AppDelegate.swift
import Cocoa
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
var mainWindowController: MainWindowController?
func applicationDidFinishLaunching(aNotification: NSNotification) {
// Insert code here to initialize your application
let mainWindowController = MainWindowController()
mainWindowController.showWindow(self)
self.mainWindowController = mainWindowController
}
func applicationWillTerminate(aNotification: NSNotification) {
// Insert code here to tear down your application
}
func applicationShouldTerminateAfterLastWindowClosed(sender: NSApplication) -> Bool {
return true
}
}
FileItem.swift
class FileItem {
var url: NSURL!
var parent: FileItem?
var isLeaf:Bool = false
static let fileManager = NSFileManager.defaultManager()
static let requiredAttributes = [NSURLIsDirectoryKey]
static let options: NSDirectoryEnumerationOptions = [.SkipsHiddenFiles, .SkipsPackageDescendants, .SkipsSubdirectoryDescendants]
lazy var children: [FileItem]? = {
if let enumerator = fileManager.enumeratorAtURL(self.url, includingPropertiesForKeys:FileItem.requiredAttributes, options: FileItem.options, errorHandler: nil) {
var files = [FileItem]()
while let localURL = enumerator.nextObject() as? NSURL {
do {
let properties = try localURL.resourceValuesForKeys(FileItem.requiredAttributes)
// check this
files.append(FileItem(url: localURL, parent: self, isLeaf: (properties[NSURLIsDirectoryKey] as! NSNumber).boolValue))
} catch {
print("Error reading file attributes")
}
}
return files
}
return nil
}()
init(url: NSURL, parent: FileItem?, isLeaf: Bool){
self.url = url
self.parent = parent
self.isLeaf = isLeaf
}
var displayName: String {
get {
return self.url.lastPathComponent!
}
}
var count: Int {
return (self.children?.count)!
}
func childAtIndex(n: Int) -> FileItem? {
return self.children![n]
}
}
I'm using MainWindowController with xib deleted provided window from app delegate and the IBOutlet for window
import Cocoa
class MainWindowController: NSWindowController {
#IBOutlet weak var outline: NSOutlineView!
private var rootItem: FileItem? = FileItem(url: NSURL(fileURLWithPath:"/"), parent: nil, isLeaf: true)
override func windowDidLoad() {
super.windowDidLoad()
// Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
}
override var windowNibName: String? {
return "MainWindowController"
}
}
//MARK: - NSOutlineViewDelegate
extension MainWindowController: NSOutlineViewDelegate {
func outlineView(outlineView: NSOutlineView, viewForTableColumn tableColumn: NSTableColumn?, item: AnyObject) -> NSView? {
let view = outline.makeViewWithIdentifier("TextCell", owner: self) as? NSTableCellView
if let it = item as? FileItem {
if let textField = view?.textField {
textField.stringValue = it.displayName
}
} else {
if let textField = view?.textField {
textField.stringValue = self.rootItem!.displayName
}
}
return view
}
}
//MARK: - NSOutlineViewDataSource
extension MainWindowController: NSOutlineViewDataSource {
func outlineView(outlineView: NSOutlineView, child index: Int, ofItem item: AnyObject?) -> AnyObject {
if let it = item as? FileItem {
return it.childAtIndex(index)!
}
return rootItem!
}
func outlineView(outlineView: NSOutlineView, numberOfChildrenOfItem item: AnyObject?) -> Int {
if let it = item as? FileItem {
return it.count
}
return 1
}
func outlineView(outlineView: NSOutlineView, isItemExpandable item: AnyObject) -> Bool {
if let it = item as? FileItem {
if it.count > 0 {
return true
}
}
return false
}
}
Example here OutlineView
It's a modified version of this example NSOutlineViewInSwift