Category Archives: iOS

Override UIWebView’s Pinch Gesture (or any gesture)

In a recent application I needed to use the UIPinchGestureRecognizer on a UIWebview. However, UIWebviews use a UIScrollView which already has a pinch gesture attached to it. I could not find a solution so I came up with this:

1. Disable the pinch gesture recognizer on the web view’s scroll view. (below)
2. Enable your own gesture recognizer

for (UIGestureRecognizer *gesture in self.webView.scrollView.gestureRecognizers) {
    if([gesture isKindOfClass:[UIPinchGestureRecognizer class]]){
        [gesture setEnabled:NO];
        break;// don't waste time once found
    }
}

When you want to re-enable the web views default functionality:

1. Disable your gesture recognizer
2. Re-enable the pinch gesture recognizer on the web view’s scroll view.

for (UIGestureRecognizer *gesture in self.webView.scrollView.gestureRecognizers) {
    if([gesture isKindOfClass:[UIPinchGestureRecognizer class]]){
        [gesture setEnabled:YES];
        break;
    }
}

 

You could also remove and store the target on the existing scroll view pinch gesture, and add your own. Then replace it again when done. There may be many more ways to do this as well.

Caution:

This involves working within the structure of UIWebview, which is not guaranteed to always be the same across various versions of iOS. In this case, scroll view is an accessed property of a web view, and gestures are always added to that subview, but Apple doesn’t guarantee this (as far as I know).

Why I don’t like the frame property

CGRect is the type for the frame property in UIViews.
Which is a c struct defined in CGGeometry.h as the following:

struct CGRect {
  CGPoint origin;
  CGSize size;
};
typedef struct CGRect CGRect

What’s wrong with frame and CGRect? I mean they were written by Apple!

I position and resize views all the time, but I very rarely do it at the same time. What I mean is I might move the view to the position (100, 50), but maintain the size. This is how:

// method 1: use the original frame
// I have 3 lines of code for 1 task
CGRect frame = view.frame;
frame.origin = CGPointMake(100, 50);
view.frame = frame;

// method 2: recreate the frame rect
// I must pass the width and height
view.frame = CGRectMake(100, 50, view.frame.size.width, view.frame.size.height);

// method 3: not legal, but how I want to do it
view.frame.origin = CGPointMake(100, 50);

It might seem I’m complaining about writing a couple extra lines of code. But currently I’m updating the whiteboard feature in my app, which is over 2500 lines of code. The extra lines are not a hassle, they are just adding more mess to scroll past, along with affecting readability.

So if CGRect was a class, it would be able to comply with KVO. As far as I know, this is the reason the frame property not assignable. This means I could change the values of the CGRect and the view can be notified to redraw. Note: the setFrame method of UIView doesn’t just set a value, but instead lets the view know to redraw with a new size.

I’m not going to end my post with just that. Here’s a solution:

// include this function in a class, or in the prefix file
CGRect CGRectMoveOrigin(CGRect rect, CGFloat x, CGFloat y)
{
  CGRect rect;
  rect.origin.x = x;
  rect.origin.y = y;
  return rect;
}

// example
view.frame = CGRectMoveOrigin(view.frame, 100, 50);

// if CGRect were KVO compliant
view.frame.origin.x = 100;
view.frame.origin.y = 50;

I am aware of CGRectOffset, but what if I don’t want to do inline math to change the position? 🙂

In the end, I’m not actually going to use my method, now. I might in future projects. There are a lot of times where I’m only changing one of the 4 values in the CGRect, which would imply I want a ton more CGRectXXX(CGRect frame, ….) functions, and I don’t want that.

But direct access to the frame’s struct would be nice.

Using MagicalRecord to wrap CoreData

My first time using CoreData, I used apple docs and CoreData methods. It was difficult at first and a lot to learn to just have a database in iOS. So with my new app I went looking for a wrapper. What I found was MagicalRecord, which seems to have a lot of following. MagicalRecord makes CoreData act like ActiveRecord, by adding the needed methods with categories. If you have used web development frameworks before you know most of them connect with the database with an active record pattern.

Although it’s not entirely active record.

Get MagicalRecord here:
https://github.com/magicalpanda/MagicalRecord

Start with the installation docs here:
https://github.com/magicalpanda/MagicalRecord/blob/develop/Docs/Installation.md

And read the rest of the docs, up a level, here:
https://github.com/magicalpanda/MagicalRecord/tree/develop/Docs

Here’s a good the starter guide by Alexander Blunck here:
http://ablfx.com/blog/article/2
But you will need to read the actual docs.