Friday, January 20, 2017

Seeing SSL content in Charles 3.11.4

- On your device you have connected to your charles (via proxy) go to charlesproxy.com/getssl
- It will ask to install a certificate, do that, then trust it.
- On your Charles, goto "SSL Proxy Settings..."
- and add the secure site you wish to be able to decrypt. No need for a port (unless you are specifically using one).
-Might need to reboot Charles but not sure for the changes to take effect.
-After that, all requests/responses from that address on that device should be readable including, content, cookies, and headers. 

Monday, March 7, 2016

Listening to all the notifications in your app

Sometimes you need to use other peoples code, sometimes you don't get to see their code (eg frameworks). Sometimes you want / need to see what is happening under the covers.

Here is a nice link that shows how to do it.
http://samjarman.co.nz/blog/quick-tip-listen-to-all-the-notifications/

in short;
NSNotificationCenter *notifyCenter = [NSNotificationCenter defaultCenter];
[notifyCenter addObserverForName:nil
object:nil
queue:nil
usingBlock:^(NSNotification* notification){
// Explore notification
NSLog(@"Notification found with:"
"\r\n name: %@"
"\r\n object: %@"
"\r\n userInfo: %@",
[notification name],
[notification object],
[notification userInfo]);
}];

Wednesday, October 7, 2015

Reveal app shows more UI details than xcode

Reveal is an app that you can get (from here) that can take a snapshot of your running app and show all the items that are in it, even if they are hidden or in the background. xcode does have "debug view hierarchy" that does a pretty good job but if you need more detail than that, reveal is for you.

In the latest xcode (7) there is a bit of a connection problem. Specifically with the plugin as it was made for xcode 5 it seems. So to manually get reveal connected to your simulation, you can pause the app while it is running and run the command in the debug commands (lldb);

expr (void*)dlopen("/Applications/Reveal.app/Contents/SharedSupport/iOS-Libraries/libReveal.dylib", 0x2);

expr [(NSNotificationCenter*)[NSNotificationCenter defaultCenter] postNotificationName:@"IBARevealRequestStart" object:nil];


continue;

You might need to enter each line one at a time for it to work. 

After that, you should be able to goto the reveal app, attach it to the simulator and hit the refresh button and tada!

Monday, September 14, 2015

My dive into KVO (Key Value Observers)

I've played with KVO for a while but was always afraid of it. Most people are I find. whenever I brought it up, people would say things like "dangerous", "spaghetti code", "it will crash your app and be impossible to debug" or just plain "messy". It is a powerful feature, but it can so easily become more of a problem than it is worth.

KVO (Key Value Observer) lets you listen for changes on an object's property. Whenever that property changes, you will get an observation notification. This can be very helpful when you are waiting for something to get updated but if you aren't careful you can really mess things up.

A few examples of things to watch out for;
-cycling, if you are listening for one property, it changes, you change your data as a result and then you changes trigger another KVO that changes other properties, which changes the properties you were listening to in the first place, bad stuff will happen.

-crashing on removal. If you try and remove the observation of a property when you were not even listening to it or worse yet, if you already stopped listening to it, it will crash your app. (People like to put @try @catch around that to avoid it but that is a lazy way of fixing it, create a bool to let you know if you already stopped listening.)

-crashing on not correct listening. When you start observing properties, it will run the observation method. This will be run on everything. If you don't account for one of the items you are listening to, or even worse, something else tells you to listen to something you are not aware of, when it goes through and doesn't do anything, it will crash your app.

-inconsistency. If you are not aware of other people KVOing your properties, you could be doing something to your properties (which you are entitled to of course because it is yours) and you might be triggering KVOs all over the place for the wrong reasons which is bad on many levels.

I am currently working with someone whom got over the hurtles and loves KVO, Here are some tips he gave me to prevent much of this from happening.

+ Try and only start and stop your KVO on the init and dealloc. If you need to stop or start listening outside of these, create a bool to mark whether or not you are currently listening.

+ Use NSCopying. This will prevent possible cycling on KVOs

 + Don't listen to overly changeable data. Any property that is mutable is probably changing way more than you need to listen for so stick to the immutable properties

+ Don't bother with contexts. keypaths should be unique enough for figuring out what you are listening to. Context add an unnecessary level of complexity to your code. If you are listening to multiple items with the same keypath, you have other issues.

So now that you are hopeful, or at least willing to try something. Here are the basics on how to implement it;

- (id)init {
    if (self = [super init]) {        
        [self addObserver:self forKeyPath:@"activeStation.playbackStatus" options:NSKeyValueObservingOptionNew context:nil];
        [self addObserver:self forKeyPath:@"activeStation" options:NSKeyValueObservingOptionNew context:nil];
    }
    return self;

}

- (void)dealloc {
    [self removeObserver:self forKeyPath:@"activeStation.playbackStatus"];
    [self removeObserver:self forKeyPath:@"activeStation"];
}


#pragma mark - KVO
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    if ([keyPath isEqualToString:@"activeStation.playbackStatus"]) {

        }
    } else if ([keyPath isEqualToString:@"activeStation"]) {

    }
}

and that is about it. When should you use KVO? Here is a link that my friend found that helps let you know. As you can see, it is limited on where to KVO but never handicap yourself just because of fear!

Thursday, July 23, 2015

iOS KVO explained or How Key Value Observations work

There are so many ways to transfer data between objects. delegate, blocks, notifications, etc. Understanding them and how to use them properly is one of the most critical aspects of developing apps. Which ones should I used and why is very important. With that being said, here is one more that I've used many times before but always seemed to avoid really understanding, until now. KVO.

Key-Value Observing (KVO) is another way to learn about other objects without them really offering it up easily. The basis of this technique is if you want to know when a value of a different object changes you can create a KVO to detect and inform you of when this actually happens. Many apple APIs use this like AVPlayer. Personally I am not a big fan but I can appreciate why it is used.

Lets get down to it. Here is the declaration;

 [object addObserver:(NSObject *)anObserver
         forKeyPath:(NSString *)keyPath
            options:(NSKeyValueObservingOptions)options
            context:(void *)context];

-object is the object you want to observe the change on
-anObserver should whom you want to be listening, usually self.
-keyPath is the name of the property you want to listen for. Example is when a label text changes you would put in @"text"
-options is for when it actually changes, what do you want back. There are 4 options of which you can choose multiple;    
    NSKeyValueObservingOptionNew = 0x01, when you want what the new value is
    NSKeyValueObservingOptionOld = 0x02, when you want what the old value was
    NSKeyValueObservingOptionInitial = 0x04, when you want to know before it happens
    NSKeyValueObservingOptionPrior  = 0x08 when you want to know after it happens (can't get the old one then)
-context is a unique identifier that you can reference when the call back method is actually called. I needs to be unique and nothing else. So people like to get creative with this sometimes. Most of the time I see something like this;


static void *AVPlayerDemoPlaybackViewControllerStatusObservationContext = &AVPlayerDemoPlaybackViewControllerStatusObservationContext;

This is just a pointer that references itself. It is small and unique so it fits perfectly. And when you want to find it, you can do so easily. 

Now that you are listening, now what? How do I actually do something? Well you need to run the actually method it plans to run when it needs to of course. It is;

- (void)observeValueForKeyPath:(NSString*) path
                      ofObject:(id)object
                        change:(NSDictionary*)change
                       context:(void*)context

-path is the string you want
-object is the actual object 
-change is a dictionary of the items you requested
-context is that unique context you created above

Since this method is called for all value changes you should isolate what you are looking for each time by referencing path, context and/or object. Once you have done that, grab the change dictionary and see what was actually changed. 

Note: Most of the time you want to compare the new and old one when you get them to make sure it was not actually just updated with the same thing twice.

   if (context == AVPlayerDemoPlaybackViewControllerStatusObservationContext){
        AVPlayerItemStatus status = [[change objectForKey:NSKeyValueChangeNewKey] integerValue];
        self.streamStatusType = StreamStatusTypeUnknownState;
        switch (status){
            case AVPlayerItemStatusUnknown:{
                self.streamStatusType = StreamStatusTypeUnknownState;
                break;
            }
            case AVPlayerItemStatusReadyToPlay:{
                self.streamStatusType = StreamStatusTypeReadyToPlay;
                break;
            }
            case AVPlayerItemStatusFailed: {
                self.streamStatusType = StreamStatusTypeFailed;
                break;
            }
        }
     }

And that is about it!

Bonus note: removing the observer can actually crash the app randomly is seems so it is good practice to add a @try @catch around it just in case.

        @try {
            [self.playerItem removeObserver:self forKeyPath:@"status"];
        }
        @catch (NSException *exception) {
            
        }
        @finally {
            

        }


References:
Apple KVO intro
Apple KVO example


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