[아이폰 앱 개발] warning: X may not reposnd to Y 관련
Originally Posted by occular 
I'm just wondering what the usual way is of fixing "warning: X may not reposnd to Y" warnings?

I can see what the problem is, just not sure of the best way to fix it...
This is a method in a controller of mine that subclasses UIViewController:

- (void)viewWillAppearBOOL)animated {
[[self view] setupAnimation];
}

The '[self view]' gives us the "UIView view" field inherited from UIViewController, and the compiler of course can't tell that the UIView in question responds to the setupAnimation message.

So what is the best way to fix this situation?
Would adding a selector check be the way forward?

thanks!
Ok, so it turns out that plain old casting is fine as the solution:

[(MyView*)[self view] setupAnimation];

For some reason I got it into my head that casting wasn't the objective c 'way' or something, but apparently that is not the case!
Posted by 오늘마감
[아이폰 앱 개발] Converting plist to binary plist- 서버측에서 objective -c로 변환후 아이폰으로 보낼때 서버측

  Converting plist to binary plist
 

Apple strongly recommends using the binary plist format when reading large XML-based data sets into iPhone apps. Among their reasoning is the fact that XML parsing is very taxing on the iPhone. However, this requires that files residing on the remote web server be converted first.

For frequently-changing content, it is not acceptable to do this manually. If at all possible, I'd like to avoid having a web based app call the command line to perform the conversion (i.e., plutil).

Are there publicly available algorithms to perform this conversion?

    264440        Brian Cline        objective-c  cocoa  cocoa-touch  iphone  core-foundation  


 

Yes. All the plist code is part of CoreFoundation, which is opensource. CoreFoundation can be directly built and run on Linux and Windows, so you can write a CF tool using the normal APIs you would use on Mac OS X, but build and run it on other platforms.

The particular API you want to be looking at is CFPropertyListWriteToStream(). The code for CoreFoundation is available from Apple (tarball), among other places.

Finally depending on how often you update the file, how much processor you have to spare on the server, and how much repetition there is your data there may be one significant enhancement left that you can do. By default certain elements in binary plists are uniqued (such as strings). Other elements are not (such as arrays and dictionarts). The binary plist format allows them to be uniqued, the issue is that it is expensive to actually walk through and unique arrays and dictionaries. If you have a lot of identical arrays or dicts in your content you may see a significant size reduction by uniquing them. You can enable that by hacking up _flattenPlist() inCFBinaryPlist.c.

If you do that make sure to test it very thoroughly, and do not do on any files you cannot update over the network, just in case a future release makes any optimizations that break that. Also, make sure you are ready to turn it off at a moments notice.

    264489        Louis Gerbarg        objective-c  cocoa  cocoa-touch  iphone  core-foundation  


  Thanks, this helps a lot. I'll probably be building this and wrapping some of these functions into a PHP module. #121576    Brian Cline


 

It's not clear if you want to do the conversion on the iPhone or on the server. If it's on the server and you can use the Cocoa frameworks, the NSPropertyListSerialization provides services to convert between the supported plist types (string, XML, and binary) on OS X (since 10.2). There are also analogous methods in the Core Foundation library if you'd prefer to use that instead.

To convert an XML plist to a binary one:

NSString *xmlPlistPath; // already set
NSString *outPath; // already set


NSData *plistData;
NSString *error;
NSPropertyListFormat format;
id plist
;
plistData
= [NSData dataWithContentsOfFile:xmlPlistPath];

plist
= [NSPropertyListSerialization propertyListFromData:plistData
mutabilityOption
:NSPropertyListImmutable
format
:&format
errorDescription
:&error];

if(plist == nil) { // unable to parse plist
//deal with failure -- error gives description of the error
} else {
binaryPlistData
= [NSPropertyListSerialization dataFromPropertyList:plist
format
:NSPropertyListBinaryFormat_v1_0
errorDescription
:&error];
if(binaryPlistData == nil) {//unable to create serialized plist
// deal with failure -- error gives description of the error
}

if(![binaryPlistData writeToFile:outPath atomically:YES]) {
// unable to write file
}
}

See Property List Pramming Guide page on developer.apple.com for more information.

Posted by 오늘마감
Convert an Image (UIImage) to Grayscale

http://iphonedevelopertips.com/

Convert an Image (UIImage) to Grayscale

Posted by 오늘마감
Adding an Activity Indicator (Spinner) to Navigation Bar

Adding an Activity Indicator (Spinner) to Navigation Bar

Posted by 오늘마감
how to make a UITextField move up when the keyboard is presented


아래 답변대로 하되 매크로설정빼먹으면 오류~ 매크로수치만큼 뷰가 위로올라간다. 뷰가 움직이는 것이 감지되나 여전히 가리면 아래 매크로값을 조정하면 된다.

일반 뷰에 텍스트필드가 있을때에도 가능하다.



#define kOFFSET_FOR_KEYBOARD 120.0

With the iPhone SDK:

I have a UIView with UITextFields that brings up a keyboard. I need it to be able to:

  1. Allow scrolling of the contents of the UIScrollView to see the other text fields once the keyboard is brought up
  2. Automatically "jump" (by scrolling up) or shortening

I know that I need a UIScrollView. I've tried changing the class of my UIView to a UIScrollView but I'm still unable to scroll the textboxes up or down.

Do I need both a UIView and a UIScrollView? Does one go inside the other? [EDIT: I now know that you want a UIView inside of a UIScrollView, and the trick is to programatically set the content size of the UIScrollView to the frame size of the UIView.]

Then what needs to be implemented in order to automatically scroll to the active text field?

Ideally as much of the setup of the components as possible will be done in Interface Builder. I'd like to only write code for what needs it.

Note: the UIView (or UIScrollView) that I'm working with is brought up by a tabbar (UITabBar), which needs to function as normal.


http://stackoverflow.com/questions/1126726/how-to-make-a-uitextfield-move-up-when-keyboard-is-present


Edit: I am adding the scroll bar just for when the keyboard comes up. Even though it's not needed, I feel like it provides a better interface because then the user can scroll and change textboxes, for example.

I've got it working where I change the frame size of the UIScrollView when the keyboard goes up and down. I'm simply using: 


-(void)textFieldDidBeginEditing:(UITextField *)textField { //Keyboard becomes visible scrollView.frame = CGRectMake(scrollView.frame.origin.x, scrollView.frame.origin.y,                                                    scrollView.frame.size.width, scrollView.frame.size.height - 215 + 50); //resize } 
-(void)textFieldDidEndEditing:(UITextField *)textField { //keyboard will hide scrollView.frame = CGRectMake(scrollView.frame.origin.x, scrollView.frame.origin.y, scrollView.frame.size.width, scrollView.frame.size.height + 215 - 50); //resize }
However this doesn't automatically "move up" or center the lower text fields in the visible area, which is what I would really like.
flag

12 Answers

9

1) You will need a scroll view if the contents you have now does not fit in iphone screen. [If you are adding the scroll view just to make the textfield scroll up when keyboard comes up, then its not needed]

2) For showing the textfields without being hidden by the keyboard, the standard way is to move up/down the view having textfields whenever the keyboard is shown

here is a sample code


-(void)textFieldDidBeginEditing:(UITextField*)sender
{
if([sender isEqual:_textField])
{
//move the main view, so that the keyboard does not hide it.
if (self.view.frame.origin.y >=0)
{
[self setViewMovedUp:YES];
}
}
}

//method to move the view up/down whenever the keyboard is shown/dismissed
-(void)setViewMovedUp:(BOOL)movedUp
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];// if you want to slide up the view

CGRect rect =self.view.frame;
if(movedUp)
{
// 1. move the view's origin up so that the text field that will be hidden come above the keyboard
// 2. increase the size of the view so that the area behind the keyboard is covered up.
rect
.origin.y -= kOFFSET_FOR_KEYBOARD;
rect
.size.height += kOFFSET_FOR_KEYBOARD;
}
else
{
// revert back to the normal state.
rect
.origin.y += kOFFSET_FOR_KEYBOARD;
rect
.size.height -= kOFFSET_FOR_KEYBOARD;
}
self.view.frame = rect;

[UIView commitAnimations];
}


-(void)keyboardWillShow:(NSNotification*)notif
{
//keyboard will be shown now. depending for which textfield is active, move up or move down the view appropriately

if([_textField isFirstResponder]&&self.view.frame.origin.y >=0)
{
[self setViewMovedUp:YES];
}
elseif(![_textField isFirstResponder]&&self.view.frame.origin.y <0)
{
[self setViewMovedUp:NO];
}
}


-(void)viewWillAppear:(BOOL)animated
{
// register for keyboard notifications
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:)
name
:UIKeyboardWillShowNotificationobject:self.view.window];
}

-(void)viewWillDisappear:(BOOL)animated
{
// unregister for keyboard notifications while not visible.
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotificationobject:nil];
}

define kOFFSET_FOR_KEYBOARD to a value as needed. like


#define kOFFSET_FOR_KEYBOARD 60.0

Hope this helps




Posted by 오늘마감
How to intercept navigation in a UIWebView

How to intercept navigation in a UIWebView

UIWebView is a great control to display formatted text (using HTML language). That text might contain links that you want to intercept in Objective-C and do a specific action (push a new view for example).

You can do this by implementing UIWebViewDelegate protocol…


- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {      NSArray *parts = [[[request URL] absoluteString] componentsSeparatedByString:@"#language_id_"];         if ([parts count] == 2) {               TranslationViewController *vc = [[TranslationViewController alloc] initWithNibName:@"PrayerTranslationView" bundle:nil];                [self presentModalViewController:vc animated:YES];              [vc release]; return FALSE;     }       return TRUE; }

In that method you can check the requested URL and decide if you want to allow the standard flow, navigation to that URL (by returning TRUE),  or do something else instead. In the example above we are showing a new view.


http://surgeworksmobile.com/iphone/how-to-intercept-navigation-in-a-uiwebview

Posted by 오늘마감
How to override UIWebView links request action with your own custom method

How to override UIWebView links request action with your own custom method

Ivan Kalaica

If you have a Web View in your view you can call a custom action when the user taps on a link in that UIWebView instance.

Here’s how…

Set the delegate of that UIWebView class instance on your instance of UIViewController class. Now just copy & paste the following code into your class.  This code implements the UIWebView instance and adds a call to the custom action (method).

- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType {
if(navigationType == UIWebViewNavigationTypeLinkClicked) {
if (overrideLinksSwitch.on == TRUE) {
[self myMethodAction];
[myWebView stopLoading];
return YES;
}
else {
<>return YES;
}
}
return YES;
}

You can download an example app here.

http://surgeworksmobile.com/iphone/how-to-override-uiwebview-links-request-action-with-your-own-custom-method
Posted by 오늘마감
[cocos2D] Easy To Create Buttons with Cocos2D

Those of you who use cocos2d a lot might understand why I created this class as some point. Hopefully it may save some of you those nasty 5 line blobs that you normally need to create a simple button. Usage is simple, just do:

[self addChild:[Button buttonWithText:@"back" atPosition:ccp(80, 50) target:self selector:@selector(back:)]]; [self addChild:[Button buttonWithImage:@"openFeint.png" atPosition:ccp(400, 50) target:self selector:@selector(openOpenFeint:)]];

You’ll need to create your own button.png and button_p.png (the second one is the image shown when you are touching the button). Also you’ll need to choose your own font. Here is the code…

// // Button.h // StickWars - Siege // // Created by EricH on 8/3/09. //   @interface Button : Menu { } + (id)buttonWithText:(NSString*)text atPosition:(CGPoint)position target:(id)target selector:(SEL)selector; + (id)buttonWithImage:(NSString*)file atPosition:(CGPoint)position target:(id)target selector:(SEL)selector; @end   @interface ButtonItem : MenuItem { Sprite *back; Sprite *backPressed; } + (id)buttonWithText:(NSString*)text target:(id)target selector:(SEL)selector; + (id)buttonWithImage:(NSString*)file target:(id)target selector:(SEL)selector; - (id)initWithText:(NSString*)text target:(id)target selector:(SEL)selector; - (id)initWithImage:(NSString*)file target:(id)target selector:(SEL)selector; @end
// // Button.m // StickWars - Siege // // Created by EricH on 8/3/09. //   #import "Button.h"     @implementation Button + (id)buttonWithText:(NSString*)text atPosition:(CGPoint)position target:(id)target selector:(SEL)selector { Menu *menu = [Menu menuWithItems:[ButtonItem buttonWithText:text target:target selector:selector], nil]; menu.position = position; return menu; }   + (id)buttonWithImage:(NSString*)file atPosition:(CGPoint)position target:(id)target selector:(SEL)selector { Menu *menu = [Menu menuWithItems:[ButtonItem buttonWithImage:file target:target selector:selector], nil]; menu.position = position; return menu; } @end   @implementation ButtonItem + (id)buttonWithText:(NSString*)text target:(id)target selector:(SEL)selector { return [[[self alloc] initWithText:text target:target selector:selector] autorelease]; }   + (id)buttonWithImage:(NSString*)file target:(id)target selector:(SEL)selector { return [[[self alloc] initWithImage:file target:target selector:selector] autorelease]; }   - (id)initWithText:(NSString*)text target:(id)target selector:(SEL)selector { if(self = [super initWithTarget:target selector:selector]) { back = [[Sprite spriteWithFile:@"button.png"] retain]; back.anchorPoint = ccp(0,0); backPressed = [[Sprite spriteWithFile:@"button_p.png"] retain]; backPressed.anchorPoint = ccp(0,0); [self addChild:back];   self.contentSize = back.contentSize;   Label* textLabel = [Label labelWithString:text fontName:@"take_out_the_garbage" fontSize:22]; textLabel.position = ccp(self.contentSize.width / 2, self.contentSize.height / 2); textLabel.anchorPoint = ccp(0.5, 0.3); [self addChild:textLabel z:1]; } return self; }   - (id)initWithImage:(NSString*)file target:(id)target selector:(SEL)selector { if(self = [super initWithTarget:target selector:selector]) {   back = [[Sprite spriteWithFile:@"button.png"] retain]; back.anchorPoint = ccp(0,0); backPressed = [[Sprite spriteWithFile:@"button_p.png"] retain]; backPressed.anchorPoint = ccp(0,0); [self addChild:back];   self.contentSize = back.contentSize;   Sprite* image = [Sprite spriteWithFile:file]; [self addChild:image z:1]; image.position = ccp(self.contentSize.width / 2, self.contentSize.height / 2); } return self; }   -(void) selected { [self removeChild:back cleanup:NO]; [self addChild:backPressed]; [super selected]; }   -(void) unselected { [self removeChild:backPressed cleanup:NO]; [self addChild:back]; [super unselected]; }   // this prevents double taps - (void)activate { [super activate]; [self setIsEnabled:NO]; [self schedule:@selector(resetButton:) interval:0.5]; }   - (void)resetButton:(ccTime)dt { [self unschedule:@selector(resetButton:)]; [self setIsEnabled:YES]; }   - (void)dealloc { [back release]; [backPressed release]; [super dealloc]; }   @end

A common question I see on the cocos2d forums is ‘when I want to make my game scroll, do I move the camera or the layer?’ or some variant of that. I also got some more detailed questions about how to make a functioning 2D scroller, so I’m going to described how I got it to work.

First of all, the answer to the above question is you move the layer. If you follow the examples in the cocos2d download, you have a “GameScene” and a “GameLayer”. Well, everything that needs to be moved when your game scrolls should be added as a child to that GameLayer. If you are using a TileMap as a background, this includes that tilemap. The only thing that you don’t add as a child to the GameLayer is stuff that does not move with the scrolling view, such as your HUDLayer that has text that shows your characters health. Other than that, your character, the background, other characters, should all be added to the GameLayer.

You have to remember which objects are absolute (attached to your GameScene or other layers) versus those that are relative (a child of your GameLayer) when you set up your touch handling code. For my HUD that has buttons you can press at any time, say to pause the game, you want to add the touch handling object to your GameScene or HUDLayer class, since it doesn’t move. But if you want to be able to touch objects that scroll along with your view in the game itself, your touch handling code needs to be in an object that is a child of your GameLayer.

This might be a little confusing, so let’s see some code:

gameLayer = [GameLayer node]; [gameScene addChild:gameLayer z:zOrder_GameLayer];   hudLayer = [HUDLayer node]; [gameScene addChild:hudLayer z:zOrder_HudLayer];   tileMap = [BGTileMap node]; [gameLayer addChild:tileMap z:-1];   [gameScene addChild:[PauseGameButton node] z:zOrder_GameButtons]; [gameLayer addChild:[FireGunAtTouchPoint node]];

The pause game button is always on your screen, while the point at which your character fires the gun depends on how how far your view has been scrolled (by moving GameLayer).

Let’s see some of the code that actually moves this game layer:

- (void)setViewpointCenter:(CGPoint)point { CGPoint centerPoint = ccp(240, 160); viewPoint = ccpSub(centerPoint, point);   // dont scroll so far so we see anywhere outside the visible map which would show up as black bars if(point.x &lt; centerPoint.x) viewPoint.x = 0; if(point.y &lt; centerPoint.y) viewPoint.y = 0;   // while zoomed out, don't adjust the viewpoint if(!isZoomedOut) gameLayer.position = viewPoint; }

When do you call that method? Well, it depends on what you want, but generally these scrolling games follow around the movement of your ‘main’ character, right? So whatever character the you want to follow, add this to override the standard CocosNode setPosition method so you update your viewpoint whenever the character moves

- (void)setPosition:(CGPoint)point { [[StandardGameController sharedSingleton] setViewpointCenter:point]; [super setPosition:point]; }

Note that the StandardGameController is a construct of mine that I use to separate the game logic out from the display code. It doesn’t matter exactly how you do it, you just need a way to have your main character object call back to something that contains a reference to GameLayer so it can adjust the position of your GameLayer.

Now remember, for your background to scroll properly, you need to add your background tileMap as a child of your GameLayer that is being moved around.

That being said, I found that an important method was missing from the cocos2d tilemap that I need to use in order to detect collisions based on the types of tiles encountered. I created a subclass of TMXTiledMap and added in these methods:

- (CGPoint)coordinatesAtPosition:(CGPoint)point { return ccp((int)(point.x / self.tileSize.width), (int)(self.mapSize.height - (point.y / self.tileSize.height))); }   - (unsigned int)getGIDAtPosition:(CGPoint)point { return [layer tileGIDAt:[self coordinatesAtPosition:point]]; }

That way it’s easy to figure out what tile any individual object is colliding with. For example, in my main character object I can have code that runs in step: function with this:

BGTileMap* tileMap = [StandardGameController sharedSingleton].tileMap; CGPoint coordinate = [tileMap coordinatesAtPosition:self.position]; BBLog(@"Right now on tile %d",[tileMap.layer tileGIDAt:coordinate]);

Now I know what type of tile I am overlapping, and I can respond to the environment accordingly.

This is really all the code that you need to make a scrolling game view…I think some people overthink it and try adjusting the position of every object individually with some offset, but it’s not necessary since your objects can use relative positions with their parent.

I have one last bit of code to add, and this is something kind of fun. It’s not complete, but at least it’s a start. What this allows you to do is ‘zoom out’ so you can see your entire map with ALL the objects shrunk down, and then zoom back in to your character. The only tricky part is when you zoom back in, you have to slowly adjust your viewpoint in steps so the zoom in action is centered on your character, instead of jumping at the end.

#define ZOOM_BACK_IN_INTERVALS 10 #define ZOOM_OUT_RATE 0.3 // TODO need to refine this so for each step it uses the new viewpoint - (void)setZoom:(BOOL)zoomedIn { BBLog(@"Zooming in %d", zoomedIn);   // this scales it out so the whole height of the tilemap is in the screen float zoomScaleFactor = 320 / (tileMap.mapSize.height * tileMap.tileSize.height); if(zoomedIn) { [gameLayer runAction:[ScaleTo actionWithDuration:ZOOM_OUT_RATE scale:1.0]]; [gameLayer runAction:[MoveTo actionWithDuration:ZOOM_OUT_RATE position:viewPoint]]; [self schedule:@selector(setZoomedBackIn:) interval:ZOOM_OUT_RATE]; // need this for the transistion } else { [gameLayer runAction:[ScaleTo actionWithDuration:ZOOM_OUT_RATE scale:zoomScaleFactor]]; [gameLayer runAction:[MoveTo actionWithDuration:ZOOM_OUT_RATE position:ccp(0,0)]]; isZoomedOut = YES; } }   // need this small correction at the end to account of the player is moving and the viewpoint has changed to avoid jitter #define ZOOM_OUT_CORRECTION_RATE 0.3 - (void)setZoomedBackIn:(ccTime)dt { [self unschedule:@selector(setZoomedBackIn:)]; [gameLayer runAction:[MoveTo actionWithDuration:ZOOM_OUT_CORRECTION_RATE position:viewPoint]]; [self schedule:@selector(setZoomedBackInFinished:) interval:ZOOM_OUT_CORRECTION_RATE]; // need this for the transistion }   - (void)setZoomedBackInFinished:(ccTime)dt { [self unschedule:@selector(setZoomedBackInFinished:)]; isZoomedOut = NO; }

Now you see why my viewPoint variable was a class member…you’ll need it for these methods to work.

The reason this code isn’t complete is when it starts zooming in, it creates the actions to zoom in on the current viewpoint, but if the player is moving by the time the zoom animation is done, that viewpoint is changed and needs to ’snap’ to the new viewpoint. That is the reason for the setZoomedBackIn: method, which really shouldn’t have to move the gameLayer anymore. However, I haven’t yet written the code to continuously create smaller move actions to take into account a moving viewpoint as the animation continues, but doing so shouldn’t be that hard. If you want to see that bit when I finish, post in the comments and I’ll add it in.

Posted by 오늘마감
Convert an Image (UIImage) to Grayscale

http://iphonedevelopertips.com/

Convert an Image (UIImage) to Grayscale



출처 : http://blog.naver.com/PostList.nhn?blogId=philipousys¤tPage=45
Posted by 오늘마감
Adding an Activity Indicator (Spinner) to Navigation Bar

Adding an Activity Indicator (Spinner) to Navigation Bar



출처 : http://blog.naver.com/PostList.nhn?blogId=philipousys¤tPage=43
Posted by 오늘마감