Showing posts with label Notes. Show all posts
Showing posts with label Notes. Show all posts

Effectively render a Drop Shadow on a UIView subclass

Adding a drop shadow to your UIView subclass is as easy as the following code.

UIView *customView = [[UIView alloc] init];
...
customView.layer.shadowColor    = [[UIColor lightGrayColor] CGColor];
customView.layer.shadowOffset   = CGSizeMake(1, 1);
customView.layer.shadowOpacity  = 1.0;
customView.layer.shadowRadius   = 2.0; 
... 

While the common use case of such trick is on rendering stationary views, and no doubt it works perfectly that way, placing them inside a scrollable view like UISrollView or UITableView yields a different feel - it lags a bit when scrolling. So the way to solve this issue and keep them scrolling smoothly is to make use of UIBezierPath. You create an instance of this based on the `bounds` of the receiving view. Then set it as the `shadowPath` of the view's layer object.

UIBezierPath *path  = [UIBezierPath bezierPathWithRect:customView.bounds];
customView.layer.shadowPath = [path CGPath];

Now let's modify our base code to include the bezier path.

UIView *customView = [[UIView alloc] init];
...
UIBezierPath *path  = [UIBezierPath bezierPathWithRect:customView.bounds];
customView.layer.shadowPath = [path CGPath];

customView.layer.shadowColor    = [[UIColor lightGrayColor] CGColor];
customView.layer.shadowOffset   = CGSizeMake(1, 1);
customView.layer.shadowOpacity  = 1.0;
customView.layer.shadowRadius   = 2.0; 
... 

Trouble setting up iOS Push Notifications (APNS)

The following is caused by an invalid or outdated Provisioning Profile.
  • "no valid aps-environment entitlement found for application" (NSError displayed using NSLog)
  • "The entitlements specified in your application’s Code Signing Entitlements file do not match those specified in your provisioning profile" (displayed in Organizer window)
Take note that even if you're just updating an existing App ID in the Provisioning Portal, say you've just enabled this app's Push Notifications, you would also need to modify and re-submit the application's current Provisioning Profile (make sure that your test device is included in the list). After that, download and install this file, update Code Signing Identity section of your project's Build Settings to reflect the new profile (in xcode of course), then you're on to the next case.

Add a Group-By Scope to Yii's CActiveRecord Subclass

Yii Framework allows for named scopes to be added to a CActiveRecord's subclass (you can read more about this here). This also makes it more convenient to filter models based on a predetermined criteria. You can chain them with any filter methods of that class, and ultimately the CDbCriteria methods like `findAll()`.

To site an example, let's have a database table named `animals`. It also has the following fields: id, name, and classification. Let's fill this up with some data. I know this can still be normalized, but let's just leave it like this for the sake of simplicity.

[ 1, 'Eagle',     'Bird']
[ 2, 'Peacock',   'Bird']
[ 3, 'Kangaroo',  'Mammal']
[ 4, 'Dog',       'Mammal']
[ 5, 'Horse',     'Mammal']
[ 6, 'Snake',     'Reptile']
[ 7, 'Turtle',    'Reptile']
[ 8, 'Lizard',    'Reptile']
[ 9, 'Crocodile', 'Reptile']
[10, 'Spider',    'Arthropods']

Now, assuming we're asked to provide a summary of classifications, like return a list of classifications with a number of animals in each of them. This is how our sql query looks like if nothing else is added in the criteria.

SELECT t.classification, COUNT(*) AS animalCount
  FROM `animals` AS t
  GROUP BY t.classification
  ORDER BY animalCount DESC;

If you try to run this query, the result looks something like this.

[Reptile,     4]
[Mammal,      3]
[Bird,        2]
[Arthropods,  1]

Let's assume that we've created a model class named `Animal`, which represents our `animals` db table and has the following method which does the same thing as the aforementioned sql query. It looks like the following:

public function scopes()
{
  return array(
    'groupByClass' => array(
      'group'   => 't.classification',
      'select'  => 't.classification, COUNT(*) as animalCount',
      'order'   => 'animalCount DESC',
    ),
  );
}

This is the overriden method coming from CActiveRecord. To use this, we simply type:

Animal::method()->groupByClass()->findAll();

Then we get the same result:

[Reptile,     4]
[Mammal,      3]
[Bird,        2]
[Arthropods,  1]

You must be wondering how the heck I'm supposed to access `animalCount` alias. Well for that, we can simply add a special property. That would of course be of the same name, which is `animalCount`.

So there you have it.

Objective-C: Retain, Release, Autorelease

The rules for -retain, -release, and -autorelease are simple. If you alloc, copy, or retain something, you also need to (eventually) release or autorelease it. If you don't do any of those three things, you don't need to do any memory management at all. Not only don't need to, if you try, it messes things up.

If you alloc something, it's just like you sent -retain to the object. So you release or autorelease it. If you do a copy or a mutableCopy, it's also the same as sending a retain. So you also release or autorelease it.

If you never sent a retain (or equivalent) method to an object, then by default it is autoreleased and will go away on its own. The following example doesn't need to be released explicitly since it has already been given an -autorelease message internally. (see NSArray Class Reference -> arrayWithObjects:)
NSArray * sampleList = [NSArray arrayWithObjects:@"One", @"Two", nil];

Also, in my code I always try to release an object instead of autoreleasing it as much as possible.

The actual mechanism here is that when you call -autorelease, a pointer to the object is added to a list kept by an NSAutoreleasePool. When that pool is deallocated, every object in the list gets a -release method. Thus -autorelease is a delayed -release.