intro to ios development - goto conferencegotocon.com/dl/goto-cph-2011/slides/patricklinskey... ·...
TRANSCRIPT
![Page 1: Intro to iOS Development - GOTO Conferencegotocon.com/dl/goto-cph-2011/slides/PatrickLinskey... · 2011. 5. 12. · Message Arguments id text = [NSString stringWithFormat:@“Hello,](https://reader035.vdocument.in/reader035/viewer/2022071104/5fdde367f2bed17f5e7716a2/html5/thumbnails/1.jpg)
Intro to iOS Development
Patrick Linskey@plinskey
![Page 2: Intro to iOS Development - GOTO Conferencegotocon.com/dl/goto-cph-2011/slides/PatrickLinskey... · 2011. 5. 12. · Message Arguments id text = [NSString stringWithFormat:@“Hello,](https://reader035.vdocument.in/reader035/viewer/2022071104/5fdde367f2bed17f5e7716a2/html5/thumbnails/2.jpg)
YouEnterprise Java iOS development
![Page 3: Intro to iOS Development - GOTO Conferencegotocon.com/dl/goto-cph-2011/slides/PatrickLinskey... · 2011. 5. 12. · Message Arguments id text = [NSString stringWithFormat:@“Hello,](https://reader035.vdocument.in/reader035/viewer/2022071104/5fdde367f2bed17f5e7716a2/html5/thumbnails/3.jpg)
Me
Patrick Linskey@plinskey
http://versly.com
![Page 4: Intro to iOS Development - GOTO Conferencegotocon.com/dl/goto-cph-2011/slides/PatrickLinskey... · 2011. 5. 12. · Message Arguments id text = [NSString stringWithFormat:@“Hello,](https://reader035.vdocument.in/reader035/viewer/2022071104/5fdde367f2bed17f5e7716a2/html5/thumbnails/4.jpg)
Objective C Primer
• Object-oriented extension of C
• Smalltalk-like syntax
• “Full” C compatibility
![Page 5: Intro to iOS Development - GOTO Conferencegotocon.com/dl/goto-cph-2011/slides/PatrickLinskey... · 2011. 5. 12. · Message Arguments id text = [NSString stringWithFormat:@“Hello,](https://reader035.vdocument.in/reader035/viewer/2022071104/5fdde367f2bed17f5e7716a2/html5/thumbnails/5.jpg)
[object message]
• Messages, not methods
• Braces at the beginning, which is weird.
id list = [[NSArray alloc] init];
![Page 6: Intro to iOS Development - GOTO Conferencegotocon.com/dl/goto-cph-2011/slides/PatrickLinskey... · 2011. 5. 12. · Message Arguments id text = [NSString stringWithFormat:@“Hello,](https://reader035.vdocument.in/reader035/viewer/2022071104/5fdde367f2bed17f5e7716a2/html5/thumbnails/6.jpg)
Message Arguments
id text = [NSString stringWithFormat:@“Hello, %@!”,
@“Copenhagen”];
• Arguments are embedded in the message signature
• Akin to named parameters, but order is fixed
• Type overloading is unsupported
![Page 7: Intro to iOS Development - GOTO Conferencegotocon.com/dl/goto-cph-2011/slides/PatrickLinskey... · 2011. 5. 12. · Message Arguments id text = [NSString stringWithFormat:@“Hello,](https://reader035.vdocument.in/reader035/viewer/2022071104/5fdde367f2bed17f5e7716a2/html5/thumbnails/7.jpg)
Legacy C issues
• Header files
• Single-pass compilation
• Forward-declare private messages, or careful class file definition ordering
![Page 8: Intro to iOS Development - GOTO Conferencegotocon.com/dl/goto-cph-2011/slides/PatrickLinskey... · 2011. 5. 12. · Message Arguments id text = [NSString stringWithFormat:@“Hello,](https://reader035.vdocument.in/reader035/viewer/2022071104/5fdde367f2bed17f5e7716a2/html5/thumbnails/8.jpg)
@ Directives
• Objective C preprocessor directives
• Strings: @“foo”
• Properties: @property, @synthesize
• Multi-threading: @synchronized
• etc.
![Page 9: Intro to iOS Development - GOTO Conferencegotocon.com/dl/goto-cph-2011/slides/PatrickLinskey... · 2011. 5. 12. · Message Arguments id text = [NSString stringWithFormat:@“Hello,](https://reader035.vdocument.in/reader035/viewer/2022071104/5fdde367f2bed17f5e7716a2/html5/thumbnails/9.jpg)
ArchitectureJEE
JSPJSPJSP
Servlet
JAXJAXJAX
EJBEJBEJB
Logic
Entity
Store
Presentation Business Integration
![Page 10: Intro to iOS Development - GOTO Conferencegotocon.com/dl/goto-cph-2011/slides/PatrickLinskey... · 2011. 5. 12. · Message Arguments id text = [NSString stringWithFormat:@“Hello,](https://reader035.vdocument.in/reader035/viewer/2022071104/5fdde367f2bed17f5e7716a2/html5/thumbnails/10.jpg)
ArchitectureiOS
Logic
Entity
Store
EIS
Widget
View
ModelView Controller
ViewController
![Page 11: Intro to iOS Development - GOTO Conferencegotocon.com/dl/goto-cph-2011/slides/PatrickLinskey... · 2011. 5. 12. · Message Arguments id text = [NSString stringWithFormat:@“Hello,](https://reader035.vdocument.in/reader035/viewer/2022071104/5fdde367f2bed17f5e7716a2/html5/thumbnails/11.jpg)
Model
View
Controller
MVC
![Page 12: Intro to iOS Development - GOTO Conferencegotocon.com/dl/goto-cph-2011/slides/PatrickLinskey... · 2011. 5. 12. · Message Arguments id text = [NSString stringWithFormat:@“Hello,](https://reader035.vdocument.in/reader035/viewer/2022071104/5fdde367f2bed17f5e7716a2/html5/thumbnails/12.jpg)
ViewVRoot View
Image View Control View
Play Button Pause Button
Tree
![Page 13: Intro to iOS Development - GOTO Conferencegotocon.com/dl/goto-cph-2011/slides/PatrickLinskey... · 2011. 5. 12. · Message Arguments id text = [NSString stringWithFormat:@“Hello,](https://reader035.vdocument.in/reader035/viewer/2022071104/5fdde367f2bed17f5e7716a2/html5/thumbnails/13.jpg)
V Layout
![Page 14: Intro to iOS Development - GOTO Conferencegotocon.com/dl/goto-cph-2011/slides/PatrickLinskey... · 2011. 5. 12. · Message Arguments id text = [NSString stringWithFormat:@“Hello,](https://reader035.vdocument.in/reader035/viewer/2022071104/5fdde367f2bed17f5e7716a2/html5/thumbnails/14.jpg)
int height = view.height;int height = [view height];int width = view.width;int width = [view width];
Cint width = view.getWidth();int height = view.getHeight();view.setSize(10, 20);
[view setWidth:10 height:20];
ObjC Syntax
![Page 15: Intro to iOS Development - GOTO Conferencegotocon.com/dl/goto-cph-2011/slides/PatrickLinskey... · 2011. 5. 12. · Message Arguments id text = [NSString stringWithFormat:@“Hello,](https://reader035.vdocument.in/reader035/viewer/2022071104/5fdde367f2bed17f5e7716a2/html5/thumbnails/15.jpg)
Listeners vs ActionsCbutton.setOnClickListener(new OnClickListener() { @Override public void onClick(Event e) { doSomething(); }});
[button addTarget:self action:@selector(doSomething) forControlEvents:TouchUpInside];
![Page 16: Intro to iOS Development - GOTO Conferencegotocon.com/dl/goto-cph-2011/slides/PatrickLinskey... · 2011. 5. 12. · Message Arguments id text = [NSString stringWithFormat:@“Hello,](https://reader035.vdocument.in/reader035/viewer/2022071104/5fdde367f2bed17f5e7716a2/html5/thumbnails/16.jpg)
C Notifications
NotificationCenterSender Observer
![Page 17: Intro to iOS Development - GOTO Conferencegotocon.com/dl/goto-cph-2011/slides/PatrickLinskey... · 2011. 5. 12. · Message Arguments id text = [NSString stringWithFormat:@“Hello,](https://reader035.vdocument.in/reader035/viewer/2022071104/5fdde367f2bed17f5e7716a2/html5/thumbnails/17.jpg)
NotificationsC[[NotificationCenter defaultCenter] postNotificationName:PersonDidDeleteNotification object:person];
. . .[[NotificationCenter defaultCenter] addObserver:self selector:@selector(personDidDelete:) name:PersonDidDeleteNotification object:nil];
. . .- (void)personDidDelete:(Notification*)notification { Person *person = [notification object]; ...}
![Page 18: Intro to iOS Development - GOTO Conferencegotocon.com/dl/goto-cph-2011/slides/PatrickLinskey... · 2011. 5. 12. · Message Arguments id text = [NSString stringWithFormat:@“Hello,](https://reader035.vdocument.in/reader035/viewer/2022071104/5fdde367f2bed17f5e7716a2/html5/thumbnails/18.jpg)
DelegatesC@protocol ListViewDelegate
- (int)numberOfItemsInListView:(ListView*)list;- (ListItem*)listView:(ListView*)list itemAtIndex:(int)i;...
@optional
- (void)listView:(ListView*)list didSelectItemAtIndex:(int)i;...
@end
![Page 19: Intro to iOS Development - GOTO Conferencegotocon.com/dl/goto-cph-2011/slides/PatrickLinskey... · 2011. 5. 12. · Message Arguments id text = [NSString stringWithFormat:@“Hello,](https://reader035.vdocument.in/reader035/viewer/2022071104/5fdde367f2bed17f5e7716a2/html5/thumbnails/19.jpg)
Concurrency
Any sufficiently advanced bug is indistinguishable from a feature.
- Bruce Brown
![Page 20: Intro to iOS Development - GOTO Conferencegotocon.com/dl/goto-cph-2011/slides/PatrickLinskey... · 2011. 5. 12. · Message Arguments id text = [NSString stringWithFormat:@“Hello,](https://reader035.vdocument.in/reader035/viewer/2022071104/5fdde367f2bed17f5e7716a2/html5/thumbnails/20.jpg)
Concurrency
![Page 21: Intro to iOS Development - GOTO Conferencegotocon.com/dl/goto-cph-2011/slides/PatrickLinskey... · 2011. 5. 12. · Message Arguments id text = [NSString stringWithFormat:@“Hello,](https://reader035.vdocument.in/reader035/viewer/2022071104/5fdde367f2bed17f5e7716a2/html5/thumbnails/21.jpg)
ConcurrencyJEE
![Page 22: Intro to iOS Development - GOTO Conferencegotocon.com/dl/goto-cph-2011/slides/PatrickLinskey... · 2011. 5. 12. · Message Arguments id text = [NSString stringWithFormat:@“Hello,](https://reader035.vdocument.in/reader035/viewer/2022071104/5fdde367f2bed17f5e7716a2/html5/thumbnails/22.jpg)
ConcurrencyiOS
![Page 23: Intro to iOS Development - GOTO Conferencegotocon.com/dl/goto-cph-2011/slides/PatrickLinskey... · 2011. 5. 12. · Message Arguments id text = [NSString stringWithFormat:@“Hello,](https://reader035.vdocument.in/reader035/viewer/2022071104/5fdde367f2bed17f5e7716a2/html5/thumbnails/23.jpg)
Data *data = ...;id result = [self processData:data];[view display:result];[view show];
Data *data = ...;[self performSelectorInBackground:@selector(processData:) withObject:data];
. . .
ConcurrencyiOS
- (void)processData:(Data*)data { id result = ...; [self performSelectorOnMainThread:@selector(display:) withObject:result waitUntilDone:NO];}- (void)display:(id)result { [view display:result]; [view show];}
![Page 24: Intro to iOS Development - GOTO Conferencegotocon.com/dl/goto-cph-2011/slides/PatrickLinskey... · 2011. 5. 12. · Message Arguments id text = [NSString stringWithFormat:@“Hello,](https://reader035.vdocument.in/reader035/viewer/2022071104/5fdde367f2bed17f5e7716a2/html5/thumbnails/24.jpg)
[self performSelector:@selector(hideControls) withObject:nil afterDelay:3.0];
. . .[busyIndicator show];[self processData:data];
ConcurrencyiOS
[Object cancelPreviousPerformRequestsWithTarget:self selector:@selector(hideControls) object:nil];
![Page 25: Intro to iOS Development - GOTO Conferencegotocon.com/dl/goto-cph-2011/slides/PatrickLinskey... · 2011. 5. 12. · Message Arguments id text = [NSString stringWithFormat:@“Hello,](https://reader035.vdocument.in/reader035/viewer/2022071104/5fdde367f2bed17f5e7716a2/html5/thumbnails/25.jpg)
ConcurrencyiOS
TouchEvent
Controller
Update Views
Idle
![Page 26: Intro to iOS Development - GOTO Conferencegotocon.com/dl/goto-cph-2011/slides/PatrickLinskey... · 2011. 5. 12. · Message Arguments id text = [NSString stringWithFormat:@“Hello,](https://reader035.vdocument.in/reader035/viewer/2022071104/5fdde367f2bed17f5e7716a2/html5/thumbnails/26.jpg)
[busyIndicator show];[self performSelector:@selector(processData:) withObject:data afterDelay:0.0];
ConcurrencyiOS
![Page 27: Intro to iOS Development - GOTO Conferencegotocon.com/dl/goto-cph-2011/slides/PatrickLinskey... · 2011. 5. 12. · Message Arguments id text = [NSString stringWithFormat:@“Hello,](https://reader035.vdocument.in/reader035/viewer/2022071104/5fdde367f2bed17f5e7716a2/html5/thumbnails/27.jpg)
ConcurrencyiOS
![Page 28: Intro to iOS Development - GOTO Conferencegotocon.com/dl/goto-cph-2011/slides/PatrickLinskey... · 2011. 5. 12. · Message Arguments id text = [NSString stringWithFormat:@“Hello,](https://reader035.vdocument.in/reader035/viewer/2022071104/5fdde367f2bed17f5e7716a2/html5/thumbnails/28.jpg)
ConcurrencyiOS
Queueing Model
C-level API
Blocks
![Page 29: Intro to iOS Development - GOTO Conferencegotocon.com/dl/goto-cph-2011/slides/PatrickLinskey... · 2011. 5. 12. · Message Arguments id text = [NSString stringWithFormat:@“Hello,](https://reader035.vdocument.in/reader035/viewer/2022071104/5fdde367f2bed17f5e7716a2/html5/thumbnails/29.jpg)
(^myBlock)(*myFunc)(int, int)
ConcurrencyiOS
Blocks
float = ...;= ^(int x, int y) { return x / (float)y;};
float result = myBlock(1, 2);
![Page 30: Intro to iOS Development - GOTO Conferencegotocon.com/dl/goto-cph-2011/slides/PatrickLinskey... · 2011. 5. 12. · Message Arguments id text = [NSString stringWithFormat:@“Hello,](https://reader035.vdocument.in/reader035/viewer/2022071104/5fdde367f2bed17f5e7716a2/html5/thumbnails/30.jpg)
(^myBlock)(int)
ConcurrencyiOS
Blocks
float = ^(int x) { return x / (float)y;};
float result = myBlock(1);
int y = 2;
![Page 31: Intro to iOS Development - GOTO Conferencegotocon.com/dl/goto-cph-2011/slides/PatrickLinskey... · 2011. 5. 12. · Message Arguments id text = [NSString stringWithFormat:@“Hello,](https://reader035.vdocument.in/reader035/viewer/2022071104/5fdde367f2bed17f5e7716a2/html5/thumbnails/31.jpg)
ConcurrencyiOS
Blocks
(float (^)(int)) divideByY(int y) { return ^(int x) { return x / (float)y; };}
float (^divideBy2)(int) = divideByY(2);float result = divideBy2(1);
![Page 32: Intro to iOS Development - GOTO Conferencegotocon.com/dl/goto-cph-2011/slides/PatrickLinskey... · 2011. 5. 12. · Message Arguments id text = [NSString stringWithFormat:@“Hello,](https://reader035.vdocument.in/reader035/viewer/2022071104/5fdde367f2bed17f5e7716a2/html5/thumbnails/32.jpg)
ConcurrencyiOS
Data *data = ...;id result = [self processData:data];[view display:result];[view show];
![Page 33: Intro to iOS Development - GOTO Conferencegotocon.com/dl/goto-cph-2011/slides/PatrickLinskey... · 2011. 5. 12. · Message Arguments id text = [NSString stringWithFormat:@“Hello,](https://reader035.vdocument.in/reader035/viewer/2022071104/5fdde367f2bed17f5e7716a2/html5/thumbnails/33.jpg)
iOSConcurrency
Data *data = ...;
id result = [self processData:data];dispatch_async(dispatch_get_main_queue(), ^{
});});
[view display:result];[view show];
dispatch_async(dispatch_get_global_queue(0,0), ^{
![Page 34: Intro to iOS Development - GOTO Conferencegotocon.com/dl/goto-cph-2011/slides/PatrickLinskey... · 2011. 5. 12. · Message Arguments id text = [NSString stringWithFormat:@“Hello,](https://reader035.vdocument.in/reader035/viewer/2022071104/5fdde367f2bed17f5e7716a2/html5/thumbnails/34.jpg)
iOSConcurrency
Cache *cache = ...;dispatch_queue_t cacheQ = dispatch_queue_create( “com.xyz.cache”, NULL);
. . .Record *record = ...;dispatch_async(cacheQ, ^{ [cache addRecord:record];});
. . .__block Record *result;dispatch_sync(cacheQ, ^{ result = [cache recordForKey:key];});
![Page 35: Intro to iOS Development - GOTO Conferencegotocon.com/dl/goto-cph-2011/slides/PatrickLinskey... · 2011. 5. 12. · Message Arguments id text = [NSString stringWithFormat:@“Hello,](https://reader035.vdocument.in/reader035/viewer/2022071104/5fdde367f2bed17f5e7716a2/html5/thumbnails/35.jpg)
• No garbage collection!
• Reference counting instead
• ObjC for Mac OS has GC. iOS will too (soon? http://bit.ly/95kn6f)
• Low-memory notifications
Memory
![Page 36: Intro to iOS Development - GOTO Conferencegotocon.com/dl/goto-cph-2011/slides/PatrickLinskey... · 2011. 5. 12. · Message Arguments id text = [NSString stringWithFormat:@“Hello,](https://reader035.vdocument.in/reader035/viewer/2022071104/5fdde367f2bed17f5e7716a2/html5/thumbnails/36.jpg)
Memory
alloc = create
retain = increase reference count
release = decrease reference count
autorelease = release later
1
+1
-1
-1
![Page 37: Intro to iOS Development - GOTO Conferencegotocon.com/dl/goto-cph-2011/slides/PatrickLinskey... · 2011. 5. 12. · Message Arguments id text = [NSString stringWithFormat:@“Hello,](https://reader035.vdocument.in/reader035/viewer/2022071104/5fdde367f2bed17f5e7716a2/html5/thumbnails/37.jpg)
Memory
1. [retain] what you need later
2. [release] what you alloc or retain
3. [autorelease] what you return
![Page 38: Intro to iOS Development - GOTO Conferencegotocon.com/dl/goto-cph-2011/slides/PatrickLinskey... · 2011. 5. 12. · Message Arguments id text = [NSString stringWithFormat:@“Hello,](https://reader035.vdocument.in/reader035/viewer/2022071104/5fdde367f2bed17f5e7716a2/html5/thumbnails/38.jpg)
s
@interface Person { String *_firstName; String *_lastName;}...@property String *firstName;@property String *lastName;- (String *)fullName;...@end
Memory
![Page 39: Intro to iOS Development - GOTO Conferencegotocon.com/dl/goto-cph-2011/slides/PatrickLinskey... · 2011. 5. 12. · Message Arguments id text = [NSString stringWithFormat:@“Hello,](https://reader035.vdocument.in/reader035/viewer/2022071104/5fdde367f2bed17f5e7716a2/html5/thumbnails/39.jpg)
- (void)setFirstName:(String*)newFirst {
}
Memory
[newFirst retain]; [_firstName release]; _firstName = newFirst;
![Page 40: Intro to iOS Development - GOTO Conferencegotocon.com/dl/goto-cph-2011/slides/PatrickLinskey... · 2011. 5. 12. · Message Arguments id text = [NSString stringWithFormat:@“Hello,](https://reader035.vdocument.in/reader035/viewer/2022071104/5fdde367f2bed17f5e7716a2/html5/thumbnails/40.jpg)
- (void)setFirstName:(String*)newFirst {
}
Memory
[newFirst retain]; [_firstName release];
_firstName = newFirst;
[person setFirstName [person getFirstName]];
![Page 41: Intro to iOS Development - GOTO Conferencegotocon.com/dl/goto-cph-2011/slides/PatrickLinskey... · 2011. 5. 12. · Message Arguments id text = [NSString stringWithFormat:@“Hello,](https://reader035.vdocument.in/reader035/viewer/2022071104/5fdde367f2bed17f5e7716a2/html5/thumbnails/41.jpg)
Memory
- (String *)fullName { String *full = [[String alloc] initWithFormat: “%s %s”, _firstName, _lastName]; return [full autorelease];}
![Page 42: Intro to iOS Development - GOTO Conferencegotocon.com/dl/goto-cph-2011/slides/PatrickLinskey... · 2011. 5. 12. · Message Arguments id text = [NSString stringWithFormat:@“Hello,](https://reader035.vdocument.in/reader035/viewer/2022071104/5fdde367f2bed17f5e7716a2/html5/thumbnails/42.jpg)
Memory
- (void)dealloc { [_firstName release]; [_lastName release]; [super dealloc];}
![Page 43: Intro to iOS Development - GOTO Conferencegotocon.com/dl/goto-cph-2011/slides/PatrickLinskey... · 2011. 5. 12. · Message Arguments id text = [NSString stringWithFormat:@“Hello,](https://reader035.vdocument.in/reader035/viewer/2022071104/5fdde367f2bed17f5e7716a2/html5/thumbnails/43.jpg)
Memory
Person *person = [[Person alloc] init];person.firstName = “Patrick”;person.lastName = “Linskey”;String *fullName = [person fullName];Log(fullName);[list add:person];[person release];
. . .[list remove:person];
1
0
2
1
![Page 44: Intro to iOS Development - GOTO Conferencegotocon.com/dl/goto-cph-2011/slides/PatrickLinskey... · 2011. 5. 12. · Message Arguments id text = [NSString stringWithFormat:@“Hello,](https://reader035.vdocument.in/reader035/viewer/2022071104/5fdde367f2bed17f5e7716a2/html5/thumbnails/44.jpg)
Memory
[[NotificationCenter defaultCenter] addObserver:self selector:@selector(memoryWarning:) name:MemoryWarningNotification object:nil];
. . .- (void)memoryWarning:(Notification*)notification { [cache clear]; ...}
![Page 45: Intro to iOS Development - GOTO Conferencegotocon.com/dl/goto-cph-2011/slides/PatrickLinskey... · 2011. 5. 12. · Message Arguments id text = [NSString stringWithFormat:@“Hello,](https://reader035.vdocument.in/reader035/viewer/2022071104/5fdde367f2bed17f5e7716a2/html5/thumbnails/45.jpg)
Memory
- (void)viewDidUnload { [view release]; view = nil; ... [super viewDidUnload];}
![Page 46: Intro to iOS Development - GOTO Conferencegotocon.com/dl/goto-cph-2011/slides/PatrickLinskey... · 2011. 5. 12. · Message Arguments id text = [NSString stringWithFormat:@“Hello,](https://reader035.vdocument.in/reader035/viewer/2022071104/5fdde367f2bed17f5e7716a2/html5/thumbnails/46.jpg)
Testing
• Xcode has not been a shining beacon in the darkness here
• Ships with SenTest and OCUnit
• Integration is much better than in old Xcodes (<= 3)
• GHUnit* is also popular
• Basically mandatory for old Xcodes
* https://github.com/gabriel/gh-unit
![Page 47: Intro to iOS Development - GOTO Conferencegotocon.com/dl/goto-cph-2011/slides/PatrickLinskey... · 2011. 5. 12. · Message Arguments id text = [NSString stringWithFormat:@“Hello,](https://reader035.vdocument.in/reader035/viewer/2022071104/5fdde367f2bed17f5e7716a2/html5/thumbnails/47.jpg)
The App Store
• Walled Garden
• Approval latency is unpredictable
• Fast-delivery-cycle teams will find this frustrating
![Page 48: Intro to iOS Development - GOTO Conferencegotocon.com/dl/goto-cph-2011/slides/PatrickLinskey... · 2011. 5. 12. · Message Arguments id text = [NSString stringWithFormat:@“Hello,](https://reader035.vdocument.in/reader035/viewer/2022071104/5fdde367f2bed17f5e7716a2/html5/thumbnails/48.jpg)
Beta Distribution
• Can distribute beta builds to a limited number of iOS devices*
• Consider TestFlight
https://testflightapp.com/
* 100 - 500, depending on your specifics