UIAlertView with UITextField – REJECT

A project I’m working on contains an alert that uses the addTextFieldWithValue:label: private API, this approach has been popular/recommended by a number of developers/blogs, but now that Apple have their automated checking for Private API’s any apps using this technique will be rejected….

“3.3.1 Applications may only use Documented APIs in the manner prescribed by Apple and must not use or call any private APIs.”

The following non-public APIs are included in your application:
addTextFieldWithValue:label:
textFieldAtIndex:

Jeff LaMarche has a great article that shows an alternative, that doesn’t use any Private API’s and therefore shouldn’t get you rejected.


XCode SCM column in Xcode project treeview

If you can’t see the column to the left of project files that shows the SVN status of a file, right-click the “Groups & files” title and select SCM

Groups & Files - SCM


__MyCompanyName__

The template that creates your .h and .m files within Xcode by default sets the company name to __MyCompanyName__

To correct perform the following…

1) Start up the program Terminal Utilities/Terminal
2) Enter the following where XXXXXXXXXXXXX is what you want to appear in place of __MyCompanyName__:
defaults write com.apple.Xcode PBXCustomTemplateMacroDefinitions ‘{”ORGANISATIONNAME” = “XXXXXXXXXXXXX”;}’
3) Press enter
4) Shut down and restart Xcode.


Finding Build Errors

To quickly jump to build errors within your iPhone app, use the short cut combo of ⌘=


Label with line breaks

To have a label recognise line breaks in the text that you enter in the Interface Builder, set the number of lines to 0, and when you want a new line press both the Option key and the Return key


Core Data – Updated model

After creating a new version of your data model, and adding the relevant code to handle lightweight migration, to actually get your code to run ensure that you do a clean all targets otherwise you get merge model errors!


iPhone mipmaps

Here is some code that shows the glTexParameterf values that need to be set to automatically generate mipmaps and to get OpenGL to use them

glBindTexture(GL_TEXTURE_2D, texture[0]);

//Next 2 lines are required if not mipmap
//glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
//glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

//Next 3 lines required if mipmap
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D,GL_GENERATE_MIPMAP, GL_TRUE);

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texWidth, texHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureData);


iPhone gluProject and gluUnProject

Now that I’ve started to do some OpenGL I needed to determine where in my 3D world a user had touched. In order to do this you can use a function called gluUnProject, which isn’t part of the standard framework. I’ve converted the code (so have many others) and posted it here in case it might help someone else.

I used the following article to then use this methods.

/* implementation de gluProject et gluUnproject */
/* M. Buffat 17/2/95 */

/*
 * Transform a point (column vector) by a 4x4 matrix.  I.e.  out = m * in
 * Input:  m - the 4x4 matrix
 *         in - the 4x1 vector
 * Output:  out - the resulting 4x1 vector.
 */
static void
transform_point(GLfloat out[4], const GLfloat m[16], const GLfloat in[4])
{
#define M(row,col)  m[col*4+row]
	out[0] = M(0, 0) * in[0] + M(0, 1) * in[1] + M(0, 2) * in[2] + M(0, 3) * in[3];
	out[1] = M(1, 0) * in[0] + M(1, 1) * in[1] + M(1, 2) * in[2] + M(1, 3) * in[3];
	out[2] = M(2, 0) * in[0] + M(2, 1) * in[1] + M(2, 2) * in[2] + M(2, 3) * in[3];
	out[3] = M(3, 0) * in[0] + M(3, 1) * in[1] + M(3, 2) * in[2] + M(3, 3) * in[3];
#undef M
}

/*
 * Perform a 4x4 matrix multiplication  (product = a x b).
 * Input:  a, b - matrices to multiply
 * Output:  product - product of a and b
 */
static void
matmul(GLfloat * product, const GLfloat * a, const GLfloat * b)
{
	/* This matmul was contributed by Thomas Malik */
	GLfloat temp[16];
	GLint i;

#define A(row,col)  a[(col<<2)+row]
#define B(row,col)  b[(col<<2)+row]
#define T(row,col)  temp[(col<<2)+row]

	/* i-te Zeile */
	for (i = 0; i < 4; i++) {
		T(i, 0) = A(i, 0) * B(0, 0) + A(i, 1) * B(1, 0) + A(i, 2) * B(2, 0) + A(i, 3) * B(3, 0);
		T(i, 1) = A(i, 0) * B(0, 1) + A(i, 1) * B(1, 1) + A(i, 2) * B(2, 1) + A(i, 3) * B(3, 1);
		T(i, 2) = A(i, 0) * B(0, 2) + A(i, 1) * B(1, 2) + A(i, 2) * B(2, 2) + A(i, 3) * B(3, 2);
		T(i, 3) = A(i, 0) * B(0, 3) + A(i, 1) * B(1, 3) + A(i, 2) * B(2, 3) + A(i, 3) * B(3, 3);
	}

#undef A
#undef B
#undef T
	memcpy(product, temp, 16 * sizeof(GLfloat));
}

/*
 * Compute inverse of 4x4 transformation matrix.
 * Code contributed by Jacques Leroy jle@star.be
 * Return GL_TRUE for success, GL_FALSE for failure (singular matrix)
 */
static GLboolean
invert_matrix(const GLfloat * m, GLfloat * out)
{
	/* NB. OpenGL Matrices are COLUMN major. */
#define SWAP_ROWS(a, b) { GLfloat *_tmp = a; (a)=(b); (b)=_tmp; }
#define MAT(m,r,c) (m)[(c)*4+(r)]

	GLfloat wtmp[4][8];
	GLfloat m0, m1, m2, m3, s;
	GLfloat *r0, *r1, *r2, *r3;

	r0 = wtmp[0], r1 = wtmp[1], r2 = wtmp[2], r3 = wtmp[3];

	r0[0] = MAT(m, 0, 0), r0[1] = MAT(m, 0, 1),
	r0[2] = MAT(m, 0, 2), r0[3] = MAT(m, 0, 3),
	r0[4] = 1.0f, r0[5] = r0[6] = r0[7] = 0.0f,
	r1[0] = MAT(m, 1, 0), r1[1] = MAT(m, 1, 1),
	r1[2] = MAT(m, 1, 2), r1[3] = MAT(m, 1, 3),
	r1[5] = 1.0f, r1[4] = r1[6] = r1[7] = 0.0f,
	r2[0] = MAT(m, 2, 0), r2[1] = MAT(m, 2, 1),
	r2[2] = MAT(m, 2, 2), r2[3] = MAT(m, 2, 3),
	r2[6] = 1.0f, r2[4] = r2[5] = r2[7] = 0.0f,
	r3[0] = MAT(m, 3, 0), r3[1] = MAT(m, 3, 1),
	r3[2] = MAT(m, 3, 2), r3[3] = MAT(m, 3, 3),
	r3[7] = 1.0f, r3[4] = r3[5] = r3[6] = 0.0f;

	/* choose pivot - or die */
	if (fabsf(r3[0]) > fabsf(r2[0]))
		SWAP_ROWS(r3, r2);
	if (fabsf(r2[0]) > fabsf(r1[0]))
		SWAP_ROWS(r2, r1);
	if (fabsf(r1[0]) > fabsf(r0[0]))
		SWAP_ROWS(r1, r0);
	if (0.0f == r0[0])
		return GL_FALSE;

	/* eliminate first variable     */
	m1 = r1[0] / r0[0];
	m2 = r2[0] / r0[0];
	m3 = r3[0] / r0[0];
	s = r0[1];
	r1[1] -= m1 * s;
	r2[1] -= m2 * s;
	r3[1] -= m3 * s;
	s = r0[2];
	r1[2] -= m1 * s;
	r2[2] -= m2 * s;
	r3[2] -= m3 * s;
	s = r0[3];
	r1[3] -= m1 * s;
	r2[3] -= m2 * s;
	r3[3] -= m3 * s;
	s = r0[4];
	if (s != 0.0f) {
		r1[4] -= m1 * s;
		r2[4] -= m2 * s;
		r3[4] -= m3 * s;
	}
	s = r0[5];
	if (s != 0.0f) {
		r1[5] -= m1 * s;
		r2[5] -= m2 * s;
		r3[5] -= m3 * s;
	}
	s = r0[6];
	if (s != 0.0f) {
		r1[6] -= m1 * s;
		r2[6] -= m2 * s;
		r3[6] -= m3 * s;
	}
	s = r0[7];
	if (s != 0.0f) {
		r1[7] -= m1 * s;
		r2[7] -= m2 * s;
		r3[7] -= m3 * s;
	}

	/* choose pivot - or die */
	if (fabsf(r3[1]) > fabsf(r2[1]))
		SWAP_ROWS(r3, r2);
	if (fabsf(r2[1]) > fabsf(r1[1]))
		SWAP_ROWS(r2, r1);
	if (0.0f == r1[1])
		return GL_FALSE;

	/* eliminate second variable */
	m2 = r2[1] / r1[1];
	m3 = r3[1] / r1[1];
	r2[2] -= m2 * r1[2];
	r3[2] -= m3 * r1[2];
	r2[3] -= m2 * r1[3];
	r3[3] -= m3 * r1[3];
	s = r1[4];
	if (0.0f != s) {
		r2[4] -= m2 * s;
		r3[4] -= m3 * s;
	}
	s = r1[5];
	if (0.0f != s) {
		r2[5] -= m2 * s;
		r3[5] -= m3 * s;
	}
	s = r1[6];
	if (0.0f != s) {
		r2[6] -= m2 * s;
		r3[6] -= m3 * s;
	}
	s = r1[7];
	if (0.0f != s) {
		r2[7] -= m2 * s;
		r3[7] -= m3 * s;
	}

	/* choose pivot - or die */
	if (fabsf(r3[2]) > fabsf(r2[2]))
		SWAP_ROWS(r3, r2);
	if (0.0f == r2[2])
		return GL_FALSE;

	/* eliminate third variable */
	m3 = r3[2] / r2[2];
	r3[3] -= m3 * r2[3], r3[4] -= m3 * r2[4],
	r3[5] -= m3 * r2[5], r3[6] -= m3 * r2[6], r3[7] -= m3 * r2[7];

	/* last check */
	if (0.0f == r3[3])
		return GL_FALSE;

	s = 1.0f / r3[3];		/* now back substitute row 3 */
	r3[4] *= s;
	r3[5] *= s;
	r3[6] *= s;
	r3[7] *= s;

	m2 = r2[3];			/* now back substitute row 2 */
	s = 1.0f / r2[2];
	r2[4] = s * (r2[4] - r3[4] * m2), r2[5] = s * (r2[5] - r3[5] * m2),
	r2[6] = s * (r2[6] - r3[6] * m2), r2[7] = s * (r2[7] - r3[7] * m2);
	m1 = r1[3];
	r1[4] -= r3[4] * m1, r1[5] -= r3[5] * m1,
	r1[6] -= r3[6] * m1, r1[7] -= r3[7] * m1;
	m0 = r0[3];
	r0[4] -= r3[4] * m0, r0[5] -= r3[5] * m0,
	r0[6] -= r3[6] * m0, r0[7] -= r3[7] * m0;

	m1 = r1[2];			/* now back substitute row 1 */
	s = 1.0f / r1[1];
	r1[4] = s * (r1[4] - r2[4] * m1), r1[5] = s * (r1[5] - r2[5] * m1),
	r1[6] = s * (r1[6] - r2[6] * m1), r1[7] = s * (r1[7] - r2[7] * m1);
	m0 = r0[2];
	r0[4] -= r2[4] * m0, r0[5] -= r2[5] * m0,
	r0[6] -= r2[6] * m0, r0[7] -= r2[7] * m0;

	m0 = r0[1];			/* now back substitute row 0 */
	s = 1.0f / r0[0];
	r0[4] = s * (r0[4] - r1[4] * m0), r0[5] = s * (r0[5] - r1[5] * m0),
	r0[6] = s * (r0[6] - r1[6] * m0), r0[7] = s * (r0[7] - r1[7] * m0);

	MAT(out, 0, 0) = r0[4];
	MAT(out, 0, 1) = r0[5], MAT(out, 0, 2) = r0[6];
	MAT(out, 0, 3) = r0[7], MAT(out, 1, 0) = r1[4];
	MAT(out, 1, 1) = r1[5], MAT(out, 1, 2) = r1[6];
	MAT(out, 1, 3) = r1[7], MAT(out, 2, 0) = r2[4];
	MAT(out, 2, 1) = r2[5], MAT(out, 2, 2) = r2[6];
	MAT(out, 2, 3) = r2[7], MAT(out, 3, 0) = r3[4];
	MAT(out, 3, 1) = r3[5], MAT(out, 3, 2) = r3[6];
	MAT(out, 3, 3) = r3[7];

	return GL_TRUE;

#undef MAT
#undef SWAP_ROWS
}

/* projection du point (objx,objy,obz) sur l'ecran (winx,winy,winz) */
//GLint GLAPIENTRY;
static GLboolean gluProject(GLfloat objx, GLfloat objy, GLfloat objz,
					 const GLfloat model[16], const GLfloat proj[16],
					 const GLint viewport[4],
					 GLfloat * winx, GLfloat * winy, GLfloat * winz)
{
	/* matrice de transformation */
	GLfloat in[4], out[4];

	/* initilise la matrice et le vecteur a transformer */
	in[0] = objx;
	in[1] = objy;
	in[2] = objz;
	in[3] = 1.0f;
	transform_point(out, model, in);
	transform_point(in, proj, out);

	/* d'ou le resultat normalise entre -1 et 1 */
	if (in[3] == 0.0f)
		return GL_FALSE;

	in[0] /= in[3];
	in[1] /= in[3];
	in[2] /= in[3];

	/* en coordonnees ecran */
	*winx = viewport[0] + (1.0f + in[0]) * viewport[2] / 2.0f;
	*winy = viewport[1] + (1.0f + in[1]) * viewport[3] / 2.0f;
	/* entre 0 et 1 suivant z */
	*winz = (1.0f + in[2]) / 2.0f;
	return GL_TRUE;
}

/* transformation du point ecran (winx,winy,winz) en point objet */
//GLint GLAPIENTRY
static GLboolean gluUnProject(GLfloat winx, GLfloat winy, GLfloat winz,
					   const GLfloat model[16], const GLfloat proj[16],
					   const GLint viewport[4],
					   GLfloat * objx, GLfloat * objy, GLfloat * objz)
{
	/* matrice de transformation */
	GLfloat m[16], A[16];
	GLfloat in[4], out[4];

	/* transformation coordonnees normalisees entre -1 et 1 */
	in[0] = (winx - viewport[0]) * 2.0f / viewport[2] - 1.0f;
	in[1] = (winy - viewport[1]) * 2.0f / viewport[3] - 1.0f;
	in[2] = 2.0f * winz - 1.0f;
	in[3] = 1.0f;

	/* calcul transformation inverse */
	matmul(A, proj, model);
	invert_matrix(A, m);

	/* d'ou les coordonnees objets */
	transform_point(out, m, in);
	if (out[3] == 0.0f)
		return GL_FALSE;
	*objx = out[0] / out[3];
	*objy = out[1] / out[3];
	*objz = out[2] / out[3];
	return GL_TRUE;
}


Xcode tip – use alt key for selecting code

If you have a code that is in a vertical section and you would like to select it, for copy/cut/paste/delete functions hold down the alt key while dragging your cursor over the code. The screen shot below shows me selecting //’s so that I can uncomment the code
Using alt key to select square not lines

The selection you make can also be used in pasting and will paste vertical down from your cursor point.


Found this great article that shows how to scroll the view so that a textfield is in view when the keyboard appears.

http://de-co-de.blogspot.com/2009/03/moving-uitextfield-above-keyboard.html

I’ve copied the code below so that I have a reference to it as well.

You also need to ensure the following steps are followed…

  • Make your controller implement UITextViewDelegate
  • setup your textfield’s (s) delegate to be your controller
  • in the controller @interface add an int verticalOffset
  • in the controller @implementation add the functions below
  • #pragma mark "-- text editing support --"
    // Animate the entire view up or down, to prevent the keyboard from covering the text field.
    - (void)moveView:(int)offset {
        [UIView beginAnimations:nil context:NULL];
        [UIView setAnimationDuration:0.3];
        // Make changes to the view's frame inside the animation block. They will be animated instead
        // of taking place immediately.
        CGRect rect = self.view.frame;
        rect.origin.y -= offset;
        rect.size.height += offset;
        self.view.frame = rect;
    
        [UIView commitAnimations];
    }
    
    - (BOOL)textFieldShouldReturn:(UITextField *) sender {
        [sender resignFirstResponder];
        if (verticalOffset!=0) {
            [self moveView: -verticalOffset];
            verticalOffset = 0;
        }
        return TRUE;
    }
    
    - (void)textFieldDidBeginEditing:(UITextField *)theTextField {
        int wantedOffset = theTextField.frame.origin.y-200;
        if ( wantedOffset < 0 ) {
            wantedOffset = 0;
        }
        if ( wantedOffset != verticalOffset ) {
            [self moveView: wantedOffset - verticalOffset];
            verticalOffset = wantedOffset;
        }
    }
    


Previous Entries Next Entries