Showing posts with label objective c. Show all posts
Showing posts with label objective c. Show all posts

Thursday, July 23, 2015

Creating an object with multiple delegates in iOS 8

Sometimes one delegate is just not enough and notifications are just not reliable or their timing is to unpredictable. Here comes the solution, multiple delegates! Bonus, this should be multithreading safe.

The multiple delegates still will not give you an order on which receiver gets the information first but if you want that, you aren't programming correctly.

First you need to make a delegate protocol;

@protocol AudioPlayerDelegate <NSObject>
@optional
- (void)AudioPlayer:(AudioPlayer *)audioEngine onStateChange:(StreamStatusType)state;

@end

in the interface, create the delegate calls;

//Delegates
- (void)addDelegate:(id<AudioPlayerDelegate>)aDelegate;
- (void)removeDelegate:(id<AudioPlayerDelegate>)aDelegate;

Also in the interface create a private delegate as a hashtable;

@private
  NSHashTable *delegates;

in the implementation, setup the delegates in the init;

  delegates = [NSHashTable weakObjectsHashTable];

and create the methods;

#pragma mark - Delegates

- (void)addDelegate:(id<AudioPlayerDelegate>)aDelegate {
    [delegates addObject:aDelegate];
}

- (void)removeDelegate:(id<AudioPlayerDelegate>)aDelegate {
    [delegates removeObject:aDelegate];
}

when you want to use them, here is the best and safest way to do so;

    __weak AudioPlayer *weakSelf = self;
    id<AudioPlayerDelegate> delegate = nil;
    for (delegate in [delegates copy]) {
        if (delegate && [delegate respondsToSelector:@selector(AudioPlayer:onStateChange:)]) {
            dispatch_async(dispatch_get_main_queue(), ^{
                [delegate AudioPlayer:weakSelf onStateChange:weakSelf.streamStatusType];
            });
       }
    }

This might be overkill but it is always good to be thread safe. 

And that's it! 

Wednesday, July 22, 2015

How to make a 3D planet in xcode using SceneKit

For some reason I've always wanted to create a spinning 3D globe but never had the time or ability. I decided last weekend to see if I could find someone or some way to make one. I checked all the usual places but the few I found were either overly complicated, way out of date, or no longer worked. So I decided to put my hat in the ring. I thought this might also be a good way to play with scenekit since I have never touched it before.

Wow. It worked better than I could ever imagine. Here is how to make the whole world in a few steps and about 15 lines of code.

First create a new project using scene kit. I like objective-c but you can do whatever you want with the language. You should be able to run it right away and see an airplane that you can move around the screen in 3 dimensions. Don't worry about that.

Here is the quick code;

-(void)worldSetup{
    SCNView *scnView = (SCNView *)self.view;
    
    myScene = [[SCNScene alloc] init];
    
    SCNSphere *planetSphere = [SCNSphere sphereWithRadius:5.0];
    SCNNode *sphereNode = [SCNNode nodeWithGeometry:planetSphere];
    [myScene.rootNode addChildNode:sphereNode];

    
    SCNMaterial *corona = [SCNMaterial material];
    corona.diffuse.contents = [UIImage imageNamed:@"earth"];
    corona.specular.contents = [UIColor colorWithWhite:0.6 alpha:1.0];
    corona.shininess = 0.5;
    [planetSphere removeMaterialAtIndex:0];
    planetSphere.materials = @[corona];
    
    // create and add a light to the scene
    scnView.autoenablesDefaultLighting = YES;
    
    // create and add a camera to the scene
    scnView.allowsCameraControl = true;
    
    mySphere = planetSphere;
    
    scnView.scene = myScene;
}

earth
in celebration of seeing pluto,
I added some love

Here is the alternate slightly more custom code.

-(void)worldSetup{
    SCNView *scnView = (SCNView *)self.view;
    
    myScene = [[SCNScene alloc] init];
    
    SCNSphere *planetSphere = [SCNSphere sphereWithRadius:5.0];
    SCNNode *sphereNode = [SCNNode nodeWithGeometry:planetSphere];
    [myScene.rootNode addChildNode:sphereNode];

    
    SCNMaterial *corona = [SCNMaterial material];
    corona.diffuse.contents = [UIImage imageNamed:@"earth"];
    corona.specular.contents = [UIColor colorWithWhite:0.6 alpha:1.0];
    corona.shininess = 0.5;
    [planetSphere removeMaterialAtIndex:0];
    planetSphere.materials = @[corona];
    
    // create and add a light to the scene
    SCNNode *lightNode = [SCNNode node];
    lightNode.light = [SCNLight light];
    lightNode.light.type = SCNLightTypeAmbient;
    lightNode.light.color = [UIColor colorWithWhite:0.37 alpha:1.0];
    lightNode.position = SCNVector3Make(0, 50, 50);
    [myScene.rootNode addChildNode:lightNode];
    
    SCNNode *omniLightNode = [SCNNode node];
    omniLightNode.light = [SCNLight light];
    omniLightNode.light.type = SCNLightTypeOmni;
    omniLightNode.light.color = [UIColor colorWithWhite:.70 alpha:1.0];
    omniLightNode.position = SCNVector3Make(0, 40, 40);
    [myScene.rootNode addChildNode:omniLightNode];
    
    // create and add a camera to the scene
    scnView.allowsCameraControl = true;
    
    // create and add a camera to the scene
    SCNNode *cameraNode = [SCNNode node];
    cameraNode.camera = [SCNCamera camera];
    cameraNode.position = SCNVector3Make(0, 0, 20);
    [myScene.rootNode addChildNode:cameraNode];
    
    mySphere = planetSphere;
    
    scnView.scene = myScene;
}

You still need to get an 'earth' texture from the internet somewhere, should be easy to find, probably from NASA. And that is it!

Here is a link to the app in github. https://github.com/Darkin/3DPlanet

Tuesday, February 10, 2015

Using blocks in objective-c iOS7 and iOS8

blocks are a godsend and still people are reserved in using it. Perhaps it is because they don't know how to set it up. Here is a quick example on how to set it up.

In the .h file of whatever you are creating, make a new typedef for the block;

typedef void(^myCompletion)(BOOL complete);

This line shows that this is a "myCompletion" block and has one value going into it which a bool called complete. 

Next in the .h file create the method you want with a completion block;

-(void)doMyStuff withCompletion:(myCompletion)compBlock;

Now all you have to do is create it in your .m file;

-(void)doMyStuff withCompletion:(myCompletion)compBlock{
     //do the stuff you want to do 
     if (compBlock != nil) {
         compBlock(YES);
     }
}

This will do the method and then check if the compBlock is nil (protection) and if it is not nil, perform that block of functions as well. 

Technically you can do the block anywhere in the code, I am just using completion as an example since most of the time, that is where it is used. 

Now you actually want to use this method? Simple;

[myMethod doMyStuff withCompletion:^(BOOL complete) {
     if (complete){

          self.navController.topViewController.navigationItem.titleView = logoView; 
     }
}];

and there you have it. 

if you want another version, you can look here.
Stanford also has a nice video about using existing blocks here.


Wednesday, July 24, 2013

Setting and Testing localizations in iOS 6

To Set:
http://stackoverflow.com/questions/5349066/how-to-localize-my-app-with-xcode-4

7) in your code use  NSLocalizedString(@"TEST", @"test") where the first arg is the string and the second arg is the description (optional can be nil)
1) Create strings file
2) call it "Localizable.strings"
3) fill the localizable.string with all the english terms you use in the app "TEST" = "TEST";
4) file inspector "Make Localized"
5) + add localization you want
6) add only the localizable.strings file to the list
8) translate and smile

To Test:
http://useyourloaf.com/blog/2013/07/22/using-launch-arguments-to-test-localizations.html

1) go into the current Scheme
2) goto arguments
3) add "
-AppleLanguages (Russian)" without quotes
4) click on and off to test the various languages and smile

Thursday, May 2, 2013

iOS Creating Custom Delegates in iOS6 with ARC

So you want two Objects to talk to each other more than a little bit? Here is what to do by example.  Lets say we have our MainViewController and a new SearchViewController that you want a delegate attached to it. This is all you need to do.

In SearchViewController.h
@protocol SearchViewDelegate <NSObject>
@optional
@required
-(void)didAskToSearch:(NSString*)string;
@end

@interface SearchViewController : UIViewController {
}
@property (nonatomic, assign) id <SearchViewDelegate> delegate;
@end

optional has non-required methods and required of course has required methods. 

In SearchViewController.m;
    [_delegate didAskToSearch: [self searchRequestDetails]];

this is put anywhere in the code when you want it to send the information back to the other object. 

In the MainViewController.h;
@interface MainViewController : UIViewController <SearchViewDelegate> {
}

In MainViewController.m;
SearchViewController *searcher = [[SearchViewController alloc]init];
searcher.delegate = self;

#pragma mark - SearchViewControllerDelegates
-(void)didAskToSearch:(NSString*)string{
     //do whatever you want with the string results
}

When creating the object, make sure the tell the delegate you have those methods. Then you just have to create the methods as per it is required. 

Helpful link
http://stackoverflow.com/questions/12020539/how-to-make-custom-delegate-in-ios-app