|
Not really sure whether this or the GameDev thread is the best place to post this, but I'll try my luck here first. Does anyone have experience with Game Center? This is more of a logical problem than technical, but the documentation (GameKit Guide) doesn't make a great deal of sense to me. First it states: GameKit Guide posted:In addition to using player identifiers in your interactions with Game Center, your application should also use player identifiers whenever you need to associate information with a specific player. For example, if your game stores data on a player’s device to track the player’s progress in your game, you should use player identifiers to distinguish between multiple players playing on the same device. GameKit Guide posted:As soon as your game moves to the background, the value of the local player object’s isAuthenticated property becomes invalid and remains invalid until your game moves back to the foreground, Game Kit authenticates the player, and your authentication handler is called. Your game must act as though there is not an authenticated player until your completion handler is called. Once your handler is called, the isAuthenticated property is valid again, and holds the whether a player is authenticated on the device. The first part implies that all my save data must be stored separately per-player. That's fine - at the moment my data is just in a dictionary so I can add a nested dictionary at the top level keyed by the player ID. The second part is the problem; to me this implies that if a player is in the middle of a game, sends the app to the background, then returns and completes a game before the completion handler is called (eg slow network), that progress should be saved under the 'unauthenticated' user rather than their own. From the player's view who was signed in for the start of the game, never explicitly signed out, and will be auto-signed in again seconds later this seems quite illogical. To me it makes more sense to save this progress as an unauthenticated user if I DO receive a callback to the completion handler saying the user isn't authenticated (or it's a different user), but otherwise to treat it as if the last-known player is still logged in. I guess the other way to read it is that "act as though there is not an authenticated player" is actually just referring to Game Center rather than being tied to the first quote, and means "don't make any Game Center calls until the completion handler is called", but again it feels wrong not to submit a high score that they may set in this brief window. Maybe they should be buffered up until the handler's called? Following on from hedgecore's question, being that this is my first app near to completion, is this the kind of thing that Apple would pull you up for in a review?
|
# ? Sep 3, 2012 21:50 |
|
|
# ? May 17, 2024 17:34 |
|
With regards to releasing your app, like pokeyman said, delete your DerivedData folder and rebuild from scratch before you submit your app. Put code:
Then close Xcode, open Terminal.app, and do code:
Test on as many different devices as you can. Know someone with an iPhone 3GS or original iPad? See if they'll be a tester for you. Ditto for any kids you know with an iPod Touch. A lot of iOS developers recommend TestFlight, which supposedly makes having beta testers easier (I haven't used it). I've been pretty lucky so far, and Apple hasn't rejected my apps or any of the updates I've submitted, but here's some tips I've heard from others: - Like others in this thread have said, set your release date well into the future, and set your app to be released on that date instead of as soon as it's approved. This will give you an exact date you can tell reviewers and such, and by setting it a good ways into the future you can still have time to resolve any issues without blowing your announced release date. AFAIK you can always move up the release date once Apple has approved the app. - Some have suggested that Thursday is the best day to have your app release on if you want it to be successful. I don't know if this is pure superstition or if there ever was a reason, but I've heard it from a few people. - Don't mention Android, or any other non-Apple platforms your app/game is available on. - They really mean it when they say don't use private APIs. - Some people have been lucky and had apps approved after just a few days. Others have had their apps sit in the "Waiting for Review" queue for weeks. For most people it seems to be 5-10 days. And yes, Apple reviewers work on the weekends and late at night. (I've had updates approved on Saturdays and after 9PM Pacific time). Doc Block fucked around with this message at 23:26 on Sep 3, 2012 |
# ? Sep 3, 2012 23:00 |
|
Froist posted:I guess the other way to read it is that "act as though there is not an authenticated player" is actually just referring to Game Center rather than being tied to the first quote, and means "don't make any Game Center calls until the completion handler is called", but again it feels wrong not to submit a high score that they may set in this brief window. Maybe they should be buffered up until the handler's called? Haven't spent five minutes with GameKit but this reading is how I understand it. Don't send poo poo up to Game Center until it's authenticated, and by the way it reauthenticates when entering the foreground. I'm quite certain they aren't recommending that you lose data (e.g. a high score). Buffering until Game Center authentication also makes sense if they're temporarily playing offline, so you'd probably want to do this anyway.
|
# ? Sep 4, 2012 01:53 |
|
Why might all bindings involving a certain key path suddenly stop working? I got a breakpoint set at the property, and every time it's hit, the property isn't nil, yet the stuff I have bound to it thinks it is. Edit: Turns out the null key was higher up in the path. It seems to be when I set the value via direct assignment, observers aren't notified of the change. Is using "[self setFoo:bar]" rather than "foo = bar" the general best practice? zergstain fucked around with this message at 04:26 on Sep 4, 2012 |
# ? Sep 4, 2012 03:37 |
|
pokeyman posted:The big one I guess is thoroughly test it from a completely clean build (i.e. delete DerivedData) on a device other than the one you mostly use for debugging. You don't want to get caught with e.g. an old nib hanging around on your development device that'll crash a release version. Doc Block posted:With regards to releasing your app, like pokeyman said, delete your DerivedData folder and rebuild from scratch before you submit your app. Thank you both for your tips! I already clear that folder out regularly, but it's a good reminder for me to do so before my final build. The future release date is a great idea as I do want to control it (but also want to make sure I'm approved). I've been using TestFlight and have heard nothing but success from iPhone 4/4S and iPod touch users. Gotta round out a few more things before I can try and sell 1.0, but I'm excited.
|
# ? Sep 4, 2012 04:51 |
|
tarepanda posted:What's up with AVCaptureSession blocking audio playback? Was that ever fixed? Got it. Add the AudioToolbox framework and: code:
|
# ? Sep 4, 2012 05:02 |
|
pokeyman posted:Buffering until Game Center authentication also makes sense if they're temporarily playing offline, so you'd probably want to do this anyway. See, this is kind of the issue, the documentation doesn't seem to have been updated since iOS 4. In iOS 5 they can be playing offline but you will still get a callback to your completion handler if there's enough cached info in Game Center to work out who they are. Similarly you can register high scores and even view cached leaderboard data when offline just by making the regular calls, they'll be automatically stored up and uploaded once the user's online (the documentation doesn't mention this at all, I found it out from watching one of the WWDC videos). So the only problem case is the small window between "application resume" and "completion handler called". In general what you're saying makes sense and fits with what I was thinking though, so I'll go with that.
|
# ? Sep 4, 2012 08:58 |
|
zergstain posted:Why might all bindings involving a certain key path suddenly stop working? I got a breakpoint set at the property, and every time it's hit, the property isn't nil, yet the stuff I have bound to it thinks it is. Yes. Using either of the following ensures that notifications are posted. Also of course any additional logic you may have put in your setters/getters. Objective-C code:
Presumably you have @synthesize foo = foo; with an ivar called foo? You should avoid doing that (having the property and the ivar have identical names), it only creates confusion. In newer versions of XCode you can skip @synthesize altogether and it will synthesize to _foo. You almost always want the notifications to fire. I generally only use direct access _foo = foo; in init methods before I return self.
|
# ? Sep 4, 2012 11:09 |
|
Speaking of notifications, how exactly do they work? Could I make it so that every time I change a UIImage, an associated label's text also changes?
|
# ? Sep 4, 2012 11:15 |
|
tarepanda posted:Speaking of notifications, how exactly do they work? Could I make it so that every time I change a UIImage, an associated label's text also changes? Yeah, there are many ways to do this. Personally, I would probably have the controller expose two properties/IBOutlets: the image, and its label. Bind the UI elements to those two as appropiate, and then only change them in tandem (ie make them read-only externally, and have an internal process for updating the image+label that ensures you don't accidentally only update one but not the other).
|
# ? Sep 4, 2012 11:24 |
|
Oh, shoot. I've been using notifications all this time and didn't know/forgot what they were. That's when you make an IBOutlet and connect it by right-click-dragging from the item to the IBOutlet, right?
|
# ? Sep 4, 2012 11:34 |
|
The connection itself is called a binding. This causes the UI element to be an observer of the keypath (the property name) on your object. When you change a property with the setters, it will fire a notification and also tell any observers that stuff is changed. The observer then knows to update itself.
|
# ? Sep 4, 2012 11:37 |
|
Carthag posted:Yes. Using either of the following ensures that notifications are posted. Also of course any additional logic you may have put in your setters/getters. I don't have any explicit ivars, just @property (strong) Foo *foo; in my .h and @synthesize foo; in my .m. I was wondering why it worked when I forgot @synthesize. I guess the best thing to do is take all of them out so I get an error when I try to access foo directly?
|
# ? Sep 4, 2012 14:03 |
|
Deprecated versions synthesized foo to foo unless you explicitly wrote something else, so that's probably why it worked. Ie you were actually accessing the underlying ivar instead of the property, thus no notifications. I've dropped writing out @synthesize in my own stuff. You still need @dynamic if you plan to have the getting/setting be handled at runtime.
|
# ? Sep 4, 2012 14:35 |
|
For custom getters and setters I guess I'm forced to use the _foo or self.foo notation, right? Edit: Looks like self.foo also leads to infinite recursion. What are my options? zergstain fucked around with this message at 18:46 on Sep 4, 2012 |
# ? Sep 4, 2012 18:17 |
|
I'm seeming to get some wierd poo poo going on with some string substitution.code:
The problem is, when I trap the code and dump the predicate to the console I just get (extras.pageids contains x%Dx ) and (fields.status <2) Whereas code:
(fields.owner = 321 ) and (fields.status <2) (or whatever the del.contactID is. I can see where the problem is, that fugging string aint substituting, but I'm dumb and sleep deprived and not sure the syntax to fix it, and not quite getting the joy I'm looking for out of google. Any suggestions? edit: Regarding the x232x strings, its dealing with a lovely web service I didnt write with a fairly bonkers hack to get around limitations in a serializer that shits out stuff like;- pageids = "['x1x', 'x2x']"; Its a hack that works, but yeah.. wheeee. duck monster fucked around with this message at 18:45 on Sep 4, 2012 |
# ? Sep 4, 2012 18:43 |
|
duck monster posted:I'm looking through a string for things like x235x or x543x (whatever the del.contactID number is). Maybe use %@ in the predicate and create the x%Dx string yourself. I haven't worked with predicates in a while. zergstain posted:For custom getters and setters I guess I'm forced to use the _foo or self.foo notation, right? Don't use self.foo in a custom getter/setter. self.foo is translated to [self setFoo:] or [self foo] which obviously means it will keep recursing. In a custom setter/getter, you either use an instance variable (_foo) or whatever else makes sense (I often have readonly properties that basically just provide convenience access to whatever is inside your object, for instance a calculated property; the canonical example is r/o fullName which pieces together from r/w properties firstName & lastName).
|
# ? Sep 4, 2012 18:51 |
|
tarepanda posted:Oh, shoot. I've been using notifications all this time and didn't know/forgot what they were. No.
|
# ? Sep 4, 2012 18:56 |
|
I'm using TestFlightApp and have gotten a few crash reports. One of them contains the following call stackcode:
|
# ? Sep 4, 2012 23:23 |
|
Complete and total shot in the dark: is there an autorelease pool on your non-main thread?
|
# ? Sep 4, 2012 23:33 |
|
pokeyman posted:Complete and total shot in the dark: is there an autorelease pool on your non-main thread? In that particular call stack the Notification is called with the following code code:
|
# ? Sep 4, 2012 23:58 |
|
NSNotificationCenter is synchronous, so you should be fine. I'm assuming the crash happens on the line with -postNotificationName:object:. I'm wondering if the problem is further up the call stack. What does -[AppDelegate connectionStatusChanged:] do?
|
# ? Sep 5, 2012 00:38 |
|
Carthag posted:Don't use self.foo in a custom getter/setter. self.foo is translated to [self setFoo:] or [self foo] which obviously means it will keep recursing. In a custom setter/getter, you either use an instance variable (_foo) or whatever else makes sense (I often have readonly properties that basically just provide convenience access to whatever is inside your object, for instance a calculated property; the canonical example is r/o fullName which pieces together from r/w properties firstName & lastName). One last thing for now. I've been setting a property to readonly and providing a custom set method because I need special things to happen when it changes. The readonly removes the warnings. How wrong is this? I'm not 100% sure if I should just be using nonatomic.
|
# ? Sep 5, 2012 01:16 |
|
zergstain posted:One last thing for now. I've been setting a property to readonly and providing a custom set method because I need special things to happen when it changes. The readonly removes the warnings. How wrong is this? I'm not 100% sure if I should just be using nonatomic. You can cause observers & bindings to register a change like so: Objective-C code:
Generally, the easiest thing is to have a private read/write version of the property in a class extension, like this: Objective-C code:
See also: http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/objectivec/chapters/occategories.html
|
# ? Sep 5, 2012 01:32 |
|
There actually is an external class which is calling setFoo, where foo is the property I have declared readonly. Seems the only effect that keyword has is to determine what methods get synthesized, so I get no complaints when I provide an implementation for setFoo. The warning says I need to implement a getter if I implement a setter, or declare the property as nonatomic. Is there one of those that I should be doing, or does it matter? Edit: I guess I could leave both methods synthesized and then register myself as an observer of my own key, and do the real work in my observeValueForKeyPath:ofObject:change:context, but that seems like I'd be over-engineering or something. zergstain fucked around with this message at 03:34 on Sep 5, 2012 |
# ? Sep 5, 2012 01:59 |
|
zergstain posted:The warning says I need to implement a getter if I implement a setter, or declare the property as nonatomic. Is there one of those that I should be doing, or does it matter? If you're giving either the getter or the setter a custom implementation, your class isn't really promising atomicity anymore, so you might as well make your property nonatomic. In general I would recommend making all of your properties nonatomic; it's really not a very useful feature, because atomicity on the level of a single field is very rarely a useful property of a class.
|
# ? Sep 5, 2012 03:53 |
|
rjmccall posted:If you're giving either the getter or the setter a custom implementation, your class isn't really promising atomicity anymore, so you might as well make your property nonatomic. In general I would recommend making all of your properties nonatomic; it's really not a very useful feature, because atomicity on the level of a single field is very rarely a useful property of a class. So why did Apple think it was?
|
# ? Sep 5, 2012 04:06 |
|
AFAIK it just causes the compiler to use synthesized getters/setters that won't allow a property to be changed while it's being read. In other words, thread safety for that one property. So it isn't a useless feature, but it doesn't make the whole class thread safe.
|
# ? Sep 5, 2012 05:02 |
|
zergstain posted:There actually is an external class which is calling setFoo, where foo is the property I have declared readonly. The atomicity part was answered but this seems to me like bad design. I don't know what you're trying to do, but it seems like you have a class whose property may only be changed a certain way/by a certain actor? It might be better to have the class with the property observe the external class (ie wait for notifications on a keypath), or have it be a delegate of it. Another way would be the data-source way; have the external object call -reloadData or similiar named method on your object, and the object will then go fetch what it needs. That way, you avoid relying on undocumented behavior (changing a property via a non-declared method). Here's an example of a delegate (I'm away from my dev machine so untested): Objective-C code:
|
# ? Sep 5, 2012 11:10 |
|
I'm really confused. Sometimes my app will give an out of memory warning and crash, but when I check it in profiler, it's only using 3-6 MB at the time it crashes. What gives? What should I be looking for?
|
# ? Sep 5, 2012 14:17 |
|
Carthag posted:The atomicity part was answered but this seems to me like bad design. I don't know what you're trying to do, but it seems like you have a class whose property may only be changed a certain way/by a certain actor? It might be better to have the class with the property observe the external class (ie wait for notifications on a keypath), or have it be a delegate of it. Another way would be the data-source way; have the external object call -reloadData or similiar named method on your object, and the object will then go fetch what it needs. That way, you avoid relying on undocumented behavior (changing a property via a non-declared method). Nah, I was just totally abusing the readonly specifier. I made it (and everything else) nonatomic. Anyway, I also have an NSView which has a rectangle that follows the cursor (sort of, it's on a grid). How can I make it so when I scroll the view, this rectangle stays with the cursor? It of course jumps to where it's supposed to be when a mouseMoved event is received.
|
# ? Sep 5, 2012 15:43 |
|
This might work, but there's probably a better way:Objective-C code:
|
# ? Sep 5, 2012 16:08 |
|
pokeyman posted:NSNotificationCenter is synchronous, so you should be fine. I'm assuming the crash happens on the line with -postNotificationName:object:. Here's the entire call stack. I've posted the functions in the call stack relative to my code here. code:
|
# ? Sep 5, 2012 16:45 |
|
So it looks like at least part of my problem was calling std::string( [someNSString UTF8String] ) when someNSString == nil. When using lldb as my debugger I would get crazy call stacks when the exception was thrown. If I switch back to gdb I get a nice obvious call stack which showed me the problem in about 6 seconds. Is this expected behavior for lldb? Anything I can do to make it work better? Or should I just use gdb until lldb becomes more robust?
|
# ? Sep 5, 2012 17:59 |
|
Carthag posted:This might work, but there's probably a better way: Of course, the view I need to update is the NSScrollView's document view. So if there's some message that gets sent to that view, or a notification I can register for, that would be preferable to subclassing NSScrollView for one method.
|
# ? Sep 5, 2012 19:19 |
|
Ender.uNF posted:My icon never looks right until the update goes live. Well the update has gone live, and on the store my app has the glossy effect. While you download, it has the glossy effect. And only after it's completed downloading does the effect go away. Sigh.
|
# ? Sep 5, 2012 22:26 |
|
zergstain posted:So why did Apple think it was? This was before my time, but in many ways it's a safer default if you think of properties as being primarily about external API. If you think of properties as the main way you get storage in an object, which is what they've become, it's an unfortunate choice.
|
# ? Sep 5, 2012 22:48 |
|
lord funk posted:Well the update has gone live, and on the store my app has the glossy effect. While you download, it has the glossy effect. And only after it's completed downloading does the effect go away. Sigh. See my post earlier about this.
|
# ? Sep 6, 2012 00:31 |
|
fankey posted:Here's the entire call stack. I've posted the functions in the call stack relative to my code here. I don't think you posted what the crash is exactly. Exception? Segfault? Looking at your code, I don't see anything odd. I think your best bet is to reduce it to a small test case and come on back.
|
# ? Sep 6, 2012 00:43 |
|
|
# ? May 17, 2024 17:34 |
|
I don't know what could've changed, but I'm trying to observe the selectionIndex key of an NSArraryController, and it's stopped working. The change dictionary new key object is always NSNull, and when I print the value for the key path in the debugger console, I get 0xc7. The key is NSUInteger, but I thought scalars got wrapped inside an NSNumber. That is neither a valid object address, nor a valid integer selection index. Any ideas for things to try? Edit: I forgot to mention I have NSTableColumns bound to different model keys in arrangedObjects. The NSTableView itself isn't bound to anything, and the NSArrayController's selectionIndexes isn't bound to anything either. I've tried playing around with it, but no luck. zergstain fucked around with this message at 02:57 on Sep 7, 2012 |
# ? Sep 6, 2012 21:57 |