Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
fankey
Aug 31, 2001

Can MPMoviePlayerController deal with anything other than a .m3u8 file when loading from an http server? Pointing it at a .mov, .mp4 or .m4v doesn't appear to work.

Adbot
ADBOT LOVES YOU

fankey
Aug 31, 2001

Small White Dragon posted:

I worked on a video streaming app during the iOS 2.0 - 2.2 period, and it did then.
Can you explain what you mean by this? I tried playing an .mp4 ( downloaded from here http://www.h264info.com/clips.html ) straight from an http link and I didn't have any success. I also converted it to an .m4v using Handbrake with the iPad profile and it didn't work either. Neither played when I pointed Safari straight at the url either - it just showed a 'No Play' icon. I'm pretty sure I had the MIME types correct on my server. It's possible the encoding was the problem but I'm not sure what else to try.

fankey
Aug 31, 2001

skidooer posted:

Make sure your web server supports HTTP ranges. The well known ones like Apache typically do, but if you are using something a little more esoteric, it might not.
That's probably it - all three web servers I was trying to use would probably be classified as esoteric - homemade c#, busybox and whatever is build into our NAS.

fankey
Aug 31, 2001

Has anyone attempted to use the Live555 RTSP library within an iOS app? I've gotten it to build and link to my app but I'm not sure the best way to integrate the task management. I'm guessing the correct way is to subclass TaskScheduler with something that uses the iOS scheduler but the documentation is a little sparse ( to be polite ) so if someone else has already done this work it'd be handy to look at it.

Once I'm able to receive RTP video packets, if they are in a form that can be natively decoded by the iPad ( like .h264 ) is it as easy as passing the packets off to something like a MPMoviePlayerController or will I need to link to ffmpeg or something similar to do any video decoding from a stream?

fankey
Aug 31, 2001

lord funk posted:

Finally got an iPad for development. :dance:

Is there a way to disable scroll touches in certain areas of a uiscrollview? I have vertical sliders that keep triggering the scroll action instead of changing the slider value. They're all together in a big group, so maybe I can just define a rect area that won't pass the touch to the scroll action. Anyone done this before?

Edit: it might work to put the sliders in their own uiscrollview which has scrolling disabled.
Edit: it doesn't.
Subclass UIScrollView and override touchesShouldBegin:withEvent:inContentView and return YES if you want the UIView that was touched to get it. Since you probably want quick response on your slider make sure to turn off Delay Content Touches in the scroll view or you will have to press and hold for a brief moment before the touchesShouldBegin will be called.

fankey
Aug 31, 2001

I'm trying to create a write-only property. If I just define the set* method like this
code:
@interface Foo
{
}
-(void)setBar:(NSString*)str;
@end

@implementation Foo
-(void)setBar:(NSString*)str
{
  // do something here
}
@end
and then attempt to access it
code:
Foo* someFoo;
someFoo.Bar = @"this is a test";
The complier complains that 'Request for member 'Bar' is something not a structure or union'. If I add an accessor function it works fine.
code:
@interface Foo
{
}
-(NSString*)bar;
-(void)setBar:(NSString*)str;
@end

@implementation Foo
-(NSString*)bar
{
  return @"asdf";
}
-(void)setBar:(NSString*)str
{
  // do something here
}
@end
I'd rather not have a bunch of dummy accessor functions that return garbage since I'm not storing the state - it gets passed on to another layer. Is there a way to implement write-only properties?

fankey
Aug 31, 2001

Apparently I kicked the write-only property hornets nest. I was mainly curious as to why it didn't work. Is it an intentional design choice in ObjC to fail so one cannot create write-only properties or is it a side effect of how properties are implemented?

The Property Declaration docs state that you must have both a setter and getter. Since I wasn't declaring the property explicitly I was surprised I got an error.

fankey
Aug 31, 2001

I'm displaying a UIPickerView dynamically based on a button press and want to select an item in the picker. If the orientation of the iPhone is portrait then calling [UIPickerView selectRow] works fine with animated being YES or NO. If the orientation is landscape, selectRow only works if I set animated to NO. If I attempt to animate the selection it fails and leaves the first item selected.

I'm attempting to select the item in viewDidLoad - is there a better place to do this? Here's my controller code in case it helps.

code:
#import "pickController.h"

@implementation pickController
@synthesize picker;

- (void)viewDidLoad 
{
  [super viewDidLoad];
  [picker selectRow:2 inComponent:0 animated:YES];
}

- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
  return 1;
}

- (NSInteger)pickerView:(UIPickerView *)pickerView 
numberOfRowsInComponent:(NSInteger)component
{
  return 4;
}

- (void)pickerView:(UIPickerView *)pickerView 
      didSelectRow:(NSInteger)row 
       inComponent:(NSInteger)component
{
}

- (NSString *)pickerView:(UIPickerView *)pickerView 
             titleForRow:(NSInteger)row 
            forComponent:(NSInteger)component
{
  return [NSString stringWithFormat:@"Item %i", row];
}

- (CGFloat)pickerView:(UIPickerView *)pickerView 
    widthForComponent:(NSInteger)component
{
  return 200;
}

// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation 
{
  return YES;
}


- (void)didReceiveMemoryWarning 
{
  [super didReceiveMemoryWarning];
}

- (void)viewDidUnload 
{
  self.picker = nil;
  [super viewDidUnload];
}

@end

fankey
Aug 31, 2001

If I had to guess I'd say it's more likely an issue with patent rights.

From http://www.tms.org/pubs/journals/JOM/matters/matters-9405.html

quote:

Second, the use of confidentiality agreements can prevent the forfeiture of valuable patent rights. Under U.S. law and in other countries as well, the public disclosure of an invention can be deemed as a forfeiture of patent rights in that invention. A properly drafted confidentiality agreement can avoid the undesired—and often unintentional—forfeiture of valuable patent rights.

My non-lawyer understanding is that once something is public knowledge you loose the ability to file a patent. By wrapping things up in an NDA you can claim it was still confidential and are able to file a patent. I haven't read the Apple NDA to see if this applies but I know my work has used an NDA to make sure we could still patent things before releasing a product.

fankey
Aug 31, 2001

lord funk posted:

As suggested in a WWDC video, I moved all my graphics calls to a background thread to prevent it from tying up the main thread. It's not a graphics heavy app, but I shaved 30ms off the response time for UITouch events. In the audio world that is huge!

Any chance you can point me to which video? I'm also writing an audio / control application and would be interested in checking it out.

fankey
Aug 31, 2001

Given a crash log and the .dSYM file associated with the release, what's the easiest way to symbolize the crash log? I'm using a script which uses xcrun to package my app so it's not in the Archived Applications section of Organizer. XCode 3.2.5 in case that matters.

fankey
Aug 31, 2001

We have an iOS app which is distributed through the app store. The app has settings available via the Settings pane. I have a user that has a bunch of iPads and he wants to 'lock down' our app as far as settings go - basically he doesn't want his users to be able to change the settings for our app. He'd probably be fine with locking down all the settings on the iPad. I thought the iPhone Configuration Utility would be able to handle this but I don't see any way to lock down the settings. Is there any other way to accomplish something like this?

fankey
Aug 31, 2001

I'm looking for a way to make a custom UIScrollView be 'virtualizing' but still be able to masquerade as a normal UIScrollView. By virtualizing I mean that it loads only the view that is visible ( +- a few pages ) and discards/loads views while the user is scrolling. I can override addSubView: and shove the views into my own collection but then subViews.count isn't in sync anymore and removeFromSuperview: doesn't remove them from my internal collection. Is there a way to make this work? Am I going about this the wrong way?

Here's my current code which uses dummy UIViews in place of the offscreen views. This doesn't work but shows what I'm going for.
code:
@implementation CustomScrollView

@synthesize currentPage;

- (BOOL)touchesShouldBegin:(NSSet *)touches withEvent:(UIEvent *)event inContentView:(UIView *)view
{
  BOOL ret = YES;
  if( [view respondsToSelector:@selector(acceptTouch)] )
  {
    ret = [[view performSelector:@selector(acceptTouch)] boolValue];
  }
  else ret = [super touchesShouldBegin:touches withEvent:event inContentView: view];
  return ret;
}

-(void)invalidateLayout
{
  _LastSize = CGSizeMake(0,0);
  [self layoutSubviews];
}

-(void) addSubview:(UIView *)view
{
  if( !allItems ) allItems = [[[NSMutableArray alloc] init] retain];
  [allItems addObject:view];
  // first page is special and is always there
  if( allItems.count == 1 )
  {
    [super addSubview:view];
  }
  else
  {
    [super addSubview:[[UIView alloc] init]];
  }
}

- (void)layoutSubviews
{
  // layout our subviews so they fill the screen
  CGSize sz = self.frame.size;
  if( _LastSize.width != sz.width || _LastSize.height != sz.height )
  {
    _LastSize = sz;
    CGSize sz = self.frame.size;
    double x = 0;
    for(UIView* view in self.subviews)
    {
      view.frame = CGRectMake( x, 0, sz.width, sz.height);
      x += sz.width;
    }
    self.contentSize = CGSizeMake(x, self.frame.size.height);
    [self setContentOffset:CGPointMake(sz.width*currentPage,0) animated:NO];
    currentPage = currentPage;
  }
}

-(void)setCurrentPage:(int)value
{
  currentPage = value;
  for( int ix = 0; ix < allItems.count; ++ix)
  {
    bool showPage = ix == 0 || (abs(ix - currentPage -1 ) < 2 );
    if( showPage )
    {
      // check to see if this page is alread in our subviews,
      // if not remove what's already there and add our view
      if( [allItems objectAtIndex:ix] != [self.subviews objectAtIndex:ix] )
      {
        [[self.subviews objectAtIndex:ix] removeFromSuperview];
        [self insertSubview:[allItems objectAtIndex:ix] atIndex:ix];
      }
    }
    else
    {
      // check if one of our views is now off screen and
      // needs to be removed
      if( [allItems containsObject:[self.subviews objectAtIndex:ix]] )
      {
        [[self.subviews objectAtIndex:ix] removeFromSuperview];
        [self insertSubview:[[UIView alloc] init] atIndex:ix];
      }
    }
  }
  _LastSize = CGSizeMake(0,0);
  [self layoutSubviews];
}

-(void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView
{
  CGFloat pageWidth = self.frame.size.width;
  float fractionalPage = self.contentOffset.x / pageWidth;
  NSInteger nearestNumber = lround(fractionalPage);
  if( nearestNumber != currentPage ) self.currentPage = nearestNumber;
}

fankey
Aug 31, 2001

pokeyman posted:

Check out the Advanced ScrollView Techniques WWDC 2011 session.
Thanks. While not exactly what I was looking for it did contain a few helpful techniques.

I have another question about image caching. Say I implement an image cache based on image URL and have the ability to assign weight to each cache entry. Using this weight I can order which images I would want to delete from my cache first - in my case that would be pages furthest from the currently viewed one. It seems like the right approach would be to hook didReceiveMemoryWarning and delete there. The issue is how to I now how much to delete? Ideally I don't want to delete all my images - just enough to allow me to continue to run. If I do a pass and delete the least weighted ones will I get another message letting me know I should do another pass?

Another thought I had was to just reserve a given amount of memory for the images and delete based on that. It seems a little slimy but in theory I think would work. I'd still need to clear out my cache when I get didReceiveMemoryWarning but that would just blow away everything requiring things to redownload if necessary.

fankey
Aug 31, 2001

pokeyman posted:

As far as I know there's no good way to figure out how much memory to free up on a memory warning–the OS will just terminate you if you don't free enough. I think the idea is you completely empty all memory caches on a memory warning.

I recommend you use an on-disk cache in your app's Caches folder (so iCloud/backup doesn't pick it up) and just load every image from disk. Let UIImageView deal with memory warnings, and let iOS purge the caches folder for you. One of several libraries that might help: AsyncImageView
I didn't think of loading to disk - that seems like a good idea. Unfortunately AsyncImageView has that on their TODO list. Nimbus looks like it supports that but it looks a big mess of stuff - not sure if I want to get into that. It doesn't seem like it'll be too hard to roll my own for the simple features I need. Thanks.

fankey
Aug 31, 2001

I'm trying to figure out if we need to join the MFi program to control one of our hardware products over Bluetooth. Searching the iOS developer site I get some confusing information. There is a CoreBluetooth Temperature Sensor example which says it shows how to read/write/notify a remote device. The ReadMe doesn't say anything about MFi ( although maybe it's implied? ) and just says you need a Bluetooth LE Device. This Technical Q&A says you need to join MFi to connect to something over Bluetooth but it's older than the previous link.

fankey
Aug 31, 2001

When I first started writing my app a few years ago I used the recommendations of this book and made 3 different targets - one for emulation, one for ad hoc testing and one for the app store. If I'm using XCode 4.3 is there any reason to continue doing so? The Tools Workflow Guide shows that I should just have one target and create a copy of the release configuration for submitting to the store. Having multiple targets is a pain so if I don't need to do that anymore that'd be great.

fankey
Aug 31, 2001

Anyone have any experience with CocoaAsyncSocket? I'm using the GCDAsyncSocket and am getting notifications into my object after it has been deallocated. I'm running with ARC if that matters. I am closing down my code before it gets dealloced to stop any subsequent notifications
code:
-(void)close
{
  [asyncSocket synchronouslySetDelegate:nil delegateQueue:NULL];
  [asyncSocket disconnect];
  asyncSocket = nil;
}
The delegate is stored in the socket as __weak id delegate; and the setDelegate call resolves to
code:
- (void)setDelegate:(id)newDelegate synchronously:(BOOL)synchronously
{
	dispatch_block_t block = ^{
		delegate = newDelegate;
	};
	
	if (dispatch_get_current_queue() == socketQueue) {
		block();
	}
	else {
		if (synchronously)
			dispatch_sync(socketQueue, block);
		else
			dispatch_async(socketQueue, block);
	}
}
Finally, the code that is actually calling into my code looks like
code:
	if (delegateQueue && [delegate respondsToSelector:@selector(socket:didReadData:withTag:)])
	{
		__strong id theDelegate = delegate;
		GCDAsyncReadPacket *theRead = currentRead; // Ensure currentRead retained since result may not own buffer
		
		dispatch_async(delegateQueue, ^{ @autoreleasepool {
			
			[theDelegate socket:self didReadData:result withTag:theRead->tag];
		}});
	}
Since it looks like they are checking the delegate and queue before calling ( which I have set to nil ) I'm wondering if there is a vulnerability from when it's placed in the queue to when it's called - if my object gets dealloced between those 2 events there will be issues. It's definitely deallocated - I have printouts in my code and I see a callback after the dealloc.

Any ideas what might be happening or workarounds that might be worth a shot?

fankey
Aug 31, 2001

I'm struggling with ARC issues. If I have a class which contains a pointer to another class with the default __strong attribute
code:
@interface Bar
{
}
@implementation Bar
-(void)dealloc
{
  NSLog(@"%@ dealloc", self);
}
@end

@interface Foo
{
  Bar* bar;
}
@implementation Foo

-(id) init
{
  if( self = [super init] )
  {
    bar = [[Bar alloc] init];
  }
}

-(void)dealloc
{
  NSLog(@"%@ dealloc", self);
}
@end

At the point in my code where I expect to release Foo I get the dealloc printout for Foo. The odd thing is I don't get the dealloc printout for Bar. I've combed through my code and commented out everything that could possibly be maintaining a reference to Bar.

Is there any case where deallocing Foo won't cause a dealloc on Bar ( excluding the obvious case where something else has a reference to Bar )? Are there any tools in XCode that can help trace who has a reference to Bar?

FAST EDIT:
If I add the following code to my Foo dealloc it will then dealloc Bar correctly
code:
-(void)dealloc
{
  NSLog(@"%@ dealloc", self);
  bar = nil;
}
I thought this sort of thing wasn't required with ARC - am I totally mistaken about that?


EDIT2 : Apparently having Zombies enabled was my issue ( per http://stackoverflow.com/questions/8695969/object-not-being-deleted-under-arc ).

fankey fucked around with this message at 22:34 on Aug 31, 2012

fankey
Aug 31, 2001

I'm using TestFlightApp and have gotten a few crash reports. One of them contains the following call stack
code:
0 QSys UCI 0x000b4316 testflight_backtrace + 158
1 QSys UCI 0x000b4f40 TFSignalHandler + 244
2 libsystem_c.dylib 0x33b847ec _sigtramp + 48
3 CoreFoundation 0x312b8bee CFEqual + 106
4 CoreFoundation 0x312c1906 _CFAppVersionCheckLessThan + 50
5 CoreFoundation 0x312c183a +[NSArray allocWithZone:] + 82
6 Foundation 0x36d90dde -[NSObject(NSThreadPerformAdditions) performSelectorOnMainThread:withObject:waitUntilDone:] + 46
7 QSys UCI 0x000864b8 -[AppDelegate connectionStatusChanged:] + 72
8 Foundation 0x36e1c4fe __57-[NSNotificationCenter addObserver:selector:name:object:]_block_invoke_0 + 18
...
I've searched around and can't find anything about _CFAppVersionCheckLessThan. Any idea why something might be going haywire inside that function? I thought it might be related to the iOS version but the iPad is running 5.1.1 and my app is targeting 5.0.

fankey
Aug 31, 2001

pokeyman posted:

Complete and total shot in the dark: is there an autorelease pool on your non-main thread?
My code doesn't use any autorelease pools but I'm using a GDCAsyncSocket from CocoaAsyncSocket and that does use them internally.

In that particular call stack the Notification is called with the following code
code:
-(void)setStatus:(ConnectionState)state:(NSString*)message:(bool)isPrimary
{
  ConnectionStatus* status = [[ConnectionStatus alloc] init];
  status.state = state;
  status.message = message;
  status.isPrimary = isPrimary;
  [[NSNotificationCenter defaultCenter] postNotificationName: ConnectionStatusChangedNotification
                                                      object:status];
}
When using ARC do I need to do anything to make sure my status object isn't destroyed before the Notification takes place?

fankey
Aug 31, 2001

pokeyman posted:

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?

Here's the entire call stack. I've posted the functions in the call stack relative to my code here.
code:
0 QSys UCI 0x000b4316 testflight_backtrace + 158
1 QSys UCI 0x000b4f40 TFSignalHandler + 244
2 libsystem_c.dylib 0x33b847ec _sigtramp + 48
3 CoreFoundation 0x312b8bee CFEqual + 106
4 CoreFoundation 0x312c1906 _CFAppVersionCheckLessThan + 50
5 CoreFoundation 0x312c183a +[NSArray allocWithZone:] + 82
6 Foundation 0x36d90dde -[NSObject(NSThreadPerformAdditions) performSelectorOnMainThread:withObject:waitUntilDone:] + 46
7 QSys UCI 0x000864b8 -[AppDelegate connectionStatusChanged:] + 72
8 Foundation 0x36e1c4fe __57-[NSNotificationCenter addObserver:selector:name:object:]_block_invoke_0 + 18
9 CoreFoundation 0x3133b546 ___CFXNotificationPost_block_invoke_0 + 70
10 CoreFoundation 0x312c7096 _CFXNotificationPost + 1406
11 Foundation 0x36d903ea -[NSNotificationCenter postNotificationName:object:userInfo:] + 66
12 Foundation 0x36d91c1a -[NSNotificationCenter postNotificationName:object:] + 30
13 QSys UCI 0x0009a3e4 -[RemoteConnection setStatus:::] + 204
14 QSys UCI 0x0009a588 -[RemoteConnection statusTimer:] + 308
15 Foundation 0x36e3260c __NSFireTimer + 144
16 CoreFoundation 0x31343a32 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 14
17 CoreFoundation 0x31343698 __CFRunLoopDoTimer + 364
18 CoreFoundation 0x3134226e __CFRunLoopRun + 1206
19 CoreFoundation 0x312c54a4 CFRunLoopRunSpecific + 300
20 CoreFoundation 0x312c536c CFRunLoopRunInMode + 104
21 GraphicsServices 0x3279e438 GSEventRunModal + 136
22 UIKit 0x315cacd4 UIApplicationMain + 1080
23 QSys UCI 0x00078d2e main + 26
24 QSys UCI 0x00078d0f start + 39

fankey
Aug 31, 2001

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?

fankey
Aug 31, 2001

Is there any documentation on exactly how UIImage frees up memory in low memory situations? I have a case where I'd really like it to discard the internal image data ( as per the docs ) but as far as I can tell it never frees any memory and my app crashes when run on an iPad 1.

My app dynamically loads pages of content off a server on the network. The set of pages is user defined and contains controls like faders, knobs and meters as well as graphic elements like text and images. In the case of images the app downloads the images via HTTP to a local /tmp directory and then creates UIImages using imageWithContentsOfFile:. The resultant UIImage is set as the .image of a UIImageView and that set as a subView of a UIView used for the page. Each of the page UIViews are loaded into a UIScrollView. The UIScrollView is 'virtualizing' - it dynamically adds and remove content based on what page is currently visible. Right now it's configured to load 3 pages on each side of the current page.

In the particular case I'm trying to debug the user has created a set of 52 pages, each one with a 1024x768 png image on them. I download all of the images and create my pages without an issue. As I scroll through the pages, at some point ( around page 43 or so ) I get an out of memory warning and then it crashes. I know that it wouldn't be possible to load 52 pngs of that size on an iPad 1 so that's why I was hoping that the UIImages would discard their data when not visible as I scrolled through - as far as I can tell that's not happening.

I thought maybe the fact I am removing pages from the view tree was somehow screwing up the UIImage memory management stuff but if I disable my virtualization of the UIScrollView and just load all the images at once it immediately runs out of memory. Of course that doesn't mean what I'm doing isn't causing a problem but it does show that I'll need to do something to make this work.

Any idea why my approach isn't working?

fankey
Aug 31, 2001

Doc Block posted:

You're unloading the pages once the user is past them, right? I think you said your app keeps 3 pages on each side, make sure they're getting unloaded once the user is far enough past them. You might not be unloading everything.

edit: I'm not super familiar with Instruments, but the Allocations instrument can tell you what is taking up all your memory.
Yes. I get the expected willMoveToWindow: with null for the window on the UIImageView as the user swipes through the pages - I believe that means I'm correctly unloading the pages once they get far enough past. Of course the documentation on UIImage memory management doesn't mention anything about needing the unload the images so I'm not sure if that would even be necessary.

I'm going to fire up Instruments next but I'm pretty much sure that I'm running out of memory because of the UIImages which is of no surprise if they aren't releasing memory under low memory situations.

fankey
Aug 31, 2001

Ender.uNF posted:

Are you absolutely certain you are removing the UIImageView from its super view and not holding a reference to it anywhere?

Instruments is really the answer... It should help you figure out what is sticking around.
I'm not removing the UIImageView directly from it's super view - there's a 4 view deep hierarchy between what I'm adding/removing from the UIScrollView and the UIImageView. As I said before, I am seeing the willMoveToWindow: on the UIImageView (with null as the newWindow) which I think means I'm removing it from the visual tree.

I am intentionally holding a reference to the UIImageView - I don't dealloc my 'removed' pages, I'm just removing them from the active UIView tree.

I guess I could be interpreting the documentation wrong.

quote:

In low-memory situations, image data may be purged from a UIImage object to free up memory on the system. This purging behavior affects only the image data stored internally by the UIImage object and not the object itself. When you attempt to draw an image whose data has been purged, the image object automatically reloads the data from its original file. This extra load step, however, may incur a small performance penalty.
Reading this, my hope was that the image data would be purged, hopefully on non visible UIImageViews, in low memory situations. Apparently I can't depend on that happening and will just have to clean up the UIImageViews as they get removed from the visual tree.

fankey
Aug 31, 2001

Martytoof posted:

How do you guys manage multiple NSURLConnections in the same class? Do you key off something in the connection:DidReceiveData: delegate method and route the data to the appropriate property or what? I'm coding on flu meds so if this is really obvious I apologize :(
I use [NSURLConnection sendAsynchronousRequest]. That way the class isn't a delegate - the completion block is what handles when you download the data. Something like
Objective-C code:
-(void)downloadProperty:(NSString*)propName fromUrl:(NSString*)url
{
  NSURLRequest* urlReq = [NSURLRequest requestWithURL:[NSURL URLWithString:url]
                                          cachePolicy:NSURLRequestReloadIgnoringCacheData
                                      timeoutInterval:15.0];

  [NSURLConnection sendAsynchronousRequest:urlReq
                                     queue:[NSOperationQueue mainQueue]
                         completionHandler:^(NSURLResponse * resp, NSData * fileData, NSError * err)
                         {
                           if( err )
                           {
                             NSLog(@"error downloading %@", err);
                           }
                           else
                           {
                             // you'd probably convert fileData to something useful here...
                             [self setValue:fileData forKey:propName];
                           }
                         }];
}

fankey
Aug 31, 2001

I have a UIPopoverController whose content is set to a UITableViewController. Pre iOS 7 I was able to use the following code in my class derived from UITableViewController so the Popover was automatically sized based on my content
Objective-C code:
-(CGSize) contentSizeForViewInPopover
{
  double w = 100;
  for( int ix = 0; ix < [self.tableView numberOfRowsInSection:0]; ix++ )
  {
    UITableViewCell* cell = [self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:ix inSection:0]];
    UIFont* font = cell.textLabel.font;
    // yes, the +20 was a fudge factor...
    w = fmax(w, [cell.textLabel.text sizeWithFont:font].width + 20 );
  }
  return CGSizeMake(w, self.tableView.rowHeight*[self.tableView numberOfRowsInSection:0] );
}
This doesn't work anymore in iOS 7. Since contentSizeForViewInPopover is deprecated I switched to overriding preferredContentSize but that didn't fix the issue. I was able to make the content so it was visible by using
Objective-C code:
-(CGSize) preferredContentSize
{
  // self.choices is a list of strings to display
  double w = 100;
  double h = 0;
  for( NSString* choice in self.choices )
  {
    UITableViewCell* cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
    cell.textLabel.text = choice;
    w = fmax( w, cell.frame.size.width);
    h += cell.frame.size.height;
  }
  return CGSizeMake(w, h);
}
but that seems a little ugly since it's creating a bunch of UITableViewCells and throwing them away. Is there a better way to determine the default size of a UITableViewCell?

fankey
Aug 31, 2001

pokeyman posted:

Might be getting this wrong but isn't your actual goal to make the popover the size of the table view? If so, can you lay out the table view then return its size?
I'm not sure how would I lay out the table view. I first get the preferredContentSize callback and then get numberOfSectionsInTableView/numberOfRowsInSection/cellForRowAtIndexPath so at the point where the Popover is asking for the size I haven't gotten any callbacks to let the TableView know its content.

fankey
Aug 31, 2001

NoDamage posted:

Based on your old code it looks like you want fixed height cells but a variable width table view/popover... In that case, why not use sizeWithFont: like before to determine the max width, and then get the total height using self.choices.count * self.tableView.rowHeight? You don't really need the cell since you already have the string that goes into the cell.
My old code, while it worked, was a pretty crude hack - hence the random +20 added to each width. Since Apple might change the margins on the default TableViewCellStyle in iOS 13 I'd like to actually figure out the real size of each cell.

fankey
Aug 31, 2001

pokeyman posted:

Try calling -layoutIfNeeded on the table view. And make sure it's the right width first.

The content loaded into the TableView is dynamic ( read from a remote server ). How would I go about making sure the table is the right width?

fankey
Aug 31, 2001

NoDamage posted:

Well you've got a bit of a chicken-and-egg scenario. The cell width is determined by the table width. The table width is determined by the popover size. If you want the popover width to be determined based on the width of your longest string, you're going to have to calculate that ahead of time. Otherwise, if you're okay using the default width (320) on your popover, then you can force the table view to layout in order to calculate the height like pokeyman mentioned.
My fixed code that I posted does work - if I create a UITableViewCell which isn't associated with a UITableView, it's frame appears to be correct based on the string I set. In that case the cell width is determined by the text and not the table width - it has no assocication to any table. It just seem inefficient and I was curious if there was a better way.

fankey
Aug 31, 2001

NoDamage posted:

Doesn't that just give you 320x44 for every cell though?

Oops, you're correct. It just happened that my test data fit pretty much perfectly in 320...

fankey
Aug 31, 2001

pokeyman posted:

I guess I'm not sure what you're trying to accomplish. My suggestion was to fill out your table view (remote data, local data, whatever, just -reloadData once you're ready), then lay it out at various widths until you find a bounds that suits you. If it's already visible though that's gonna look pretty stupid, so maybe you measure it using cells or asking UIKit to lay out your strings.

Also you can change the popover's content size on the fly, and animate the changes too, if that's useful.
You're confused because I'm not explaining things well enough and probably because I'm not experienced enough in iOS stuff to follow your suggestions.

Previously I was just measuring the strings to determine the width. I just didn't feel that comfortable with that approach since I had to hardcode a margin so it looked ok and at some point Apple might change the margins used by the cell. I guess one solution would be to provide my own cell style but I was hoping to get by using the default since it will better match iOSs look and feel.

fankey
Aug 31, 2001

moved to C/C++ thread since I think it's more of a POSIX sockets issue...

fankey fucked around with this message at 21:23 on Apr 18, 2014

fankey
Aug 31, 2001

Is there any way to work around the 'Multiple methods named 'x' found with mismatched result, parameter type or attributes' error? I made the unfortunate mistake of adding a scale property to a bunch of objects without a common base class and in the past I was able to iterate objects and set the scale with code like
Objective-C code:
if( [item respondsToSelector:@selector(setScale:)] )
{
  [item performSelector:@selector(setScale:) withObject:scaleFactor];
  // or
  [item setScale:scaleFactor];
}
but since upgrading to the latest version of Xcode I get the above error. It's conflicting with UIPinchGestureRecognizer and CAEmitterLayer properties. I'd rather not have to change my property to something like scaleFactor so it doesn't conflict.

fankey
Aug 31, 2001

ManicJason posted:

How many different classes with setScale? You can test for isKindOfClass and add the appropriate cast, but that still smells bad. You can cast to only one of the classes if the footprint is the same and you really want to save lines.
The error occurs even if I don't have any class of mine with setScale - just UIPinchGestureRecognizer and CAEmitterLayer conflict with each other. I think I'll just make a @protocol which all my classes implement to fix the issue but I'm still curious about my original question - it seems fragile that any class that happens to be included can break preformSelector.

fankey
Aug 31, 2001

Any recommendations on iBeacon hardware/SDK to play around with? The estimote looks pretty slick. Or maybe the kontakt? Apprently beacon companies are unable to spell anything correctly...

fankey
Aug 31, 2001

I'm attempting to draw a string ( in this case a single character of a font that contains icons ) with an outline. Using this code
code:
      CGContextSetFillColorWithColor(cg, [[UIColor redColor] CGColor]);
      CGContextSetLineWidth(cg, 1);
      CGContextSetTextDrawingMode(cg, kCGTextStroke);
      [actualIconString drawInRect:textRc withFont:font lineBreakMode:UILineBreakModeClip alignment:UITextAlignmentCenter];
      
      CGContextSetFillColorWithColor(cg, [actualIconColor CGColor]);
      CGContextSetTextDrawingMode(cg, kCGTextFill);
      [actualIconString drawInRect:textRc withFont:font lineBreakMode:UILineBreakModeClip alignment:UITextAlignmentCenter];
I get an outline but it's not uniform

For whatever reason the outline doesn't appear at the left and bottom.Is there a better way to draw text with an outline that will give me a uniform stroke?

Edit: I know a stroke of 1 will only get me a 0.5 stroke outline since the stroke should be centered on the path. A stroke of 2 has a similar ununiformity

fankey fucked around with this message at 22:08 on Jan 12, 2015

Adbot
ADBOT LOVES YOU

fankey
Aug 31, 2001

Better, but still isn't uniform.

It ends up making it look like a bezel and not an outline, which is what I'm going for.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply