forked from sunnyxx/XXNibBridge
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
允许在桥接的view.xib中指定file‘s owner (merge from rush)
- Loading branch information
Showing
5 changed files
with
245 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
// | ||
// XXNibBridge.h | ||
// | ||
// Created by sunnyxx on 14-7-2. | ||
// Copyright (c) 2014 sunnyxx. All rights reserved. | ||
// | ||
|
||
#import <Foundation/Foundation.h> | ||
|
||
@interface NSObject (XXIBLoadingConvenient) | ||
|
||
/// For convinent, using class name for identifier in IB. | ||
/// etc cell reuse id, storyboard id | ||
+ (NSString *)xx_nibID; | ||
|
||
/// UINib object with same name from main bundle | ||
+ (UINib *)xx_nib; | ||
|
||
/// Load object of this class from IB file with SAME name | ||
+ (id)xx_loadFromNibWithOwner:(id)owner; | ||
+ (id)xx_loadFromNib; // Nil owner | ||
|
||
/// Load UIViewController of this class from given storyboard name | ||
+ (id/*UIViewController*/)xx_loadFromStoryboardNamed:(NSString *)name; | ||
|
||
@end | ||
|
||
|
||
@interface UIView (XXNibBridge) | ||
|
||
/// Subclass override it to switch On/Off IB bridging. | ||
/// default -> NO | ||
+ (BOOL)xx_shouldApplyNibBridging; | ||
|
||
+ (Class)xx_ownerClass; | ||
|
||
- (id)owner; | ||
|
||
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
// | ||
// XXNibBridge.m | ||
// | ||
// Created by sunnyxx on 14-7-2. | ||
// Copyright (c) 2014 sunnyxx. All rights reserved. | ||
// | ||
|
||
#import "XXNibBridge.h" | ||
|
||
@implementation NSObject (XXNibLoading) | ||
|
||
+ (NSString *)xx_nibID | ||
{ | ||
return NSStringFromClass(self); | ||
} | ||
|
||
+ (id)xx_loadFromNibWithOwner:(id)owner | ||
{ | ||
NSArray *objects = [[self xx_nib] instantiateWithOwner:owner options:nil]; | ||
for (UIView *obj in objects) | ||
{ | ||
if ([obj isMemberOfClass:self]) | ||
{ | ||
return obj; | ||
} | ||
} | ||
return nil; | ||
} | ||
|
||
+ (id)xx_loadFromNib | ||
{ | ||
return [self xx_loadFromNibWithOwner:nil]; | ||
} | ||
|
||
+ (id)xx_loadFromStoryboardNamed:(NSString *)name | ||
{ | ||
UIStoryboard *sb = [UIStoryboard storyboardWithName:name bundle:nil]; | ||
return [sb instantiateViewControllerWithIdentifier:[self xx_nibID]]; | ||
} | ||
|
||
+ (UINib *)xx_nib | ||
{ | ||
return [UINib nibWithNibName:[self xx_nibID] bundle:nil]; | ||
} | ||
|
||
@end | ||
|
||
// Mapping flags that whether a class has been replaced | ||
|
||
static NSMutableDictionary * getIBReplaceFlagMapping() | ||
{ | ||
static NSMutableDictionary *mapping = nil; | ||
if (!mapping) | ||
{ | ||
mapping = [NSMutableDictionary dictionary]; | ||
} | ||
return mapping; | ||
} | ||
|
||
static BOOL getIBReplaceFlag(Class cls) | ||
{ | ||
NSMutableDictionary *mapping = getIBReplaceFlagMapping(); | ||
BOOL flag = [mapping[NSStringFromClass(cls)] boolValue]; | ||
return flag; | ||
} | ||
|
||
static void setIBReplaceFlag(Class cls, BOOL flag) | ||
{ | ||
NSMutableDictionary *mapping = getIBReplaceFlagMapping(); | ||
mapping[NSStringFromClass(cls)] = @(flag); | ||
} | ||
|
||
|
||
@import ObjectiveC; | ||
|
||
char *const kXXNibOwnerKey = "owner"; | ||
|
||
@implementation UIView (XXNibBridge) | ||
|
||
+ (BOOL)xx_shouldApplyNibBridging | ||
{ | ||
return NO; | ||
} | ||
|
||
+ (Class)xx_ownerClass | ||
{ | ||
return nil; | ||
} | ||
|
||
- (id)owner | ||
{ | ||
return objc_getAssociatedObject(self, kXXNibOwnerKey); | ||
} | ||
|
||
- (id)awakeAfterUsingCoder:(NSCoder *)aDecoder | ||
{ | ||
self = [super awakeAfterUsingCoder:aDecoder]; | ||
|
||
if (![[self class] xx_shouldApplyNibBridging]) | ||
{ | ||
return self; | ||
} | ||
|
||
// self will be replaced by object created from nib | ||
|
||
if (!getIBReplaceFlag([self class])) | ||
{ | ||
setIBReplaceFlag([self class], YES); | ||
|
||
Class ownerClass = [[self class] xx_ownerClass]; | ||
id owner; | ||
if (ownerClass) { | ||
owner = [[ownerClass alloc] initWithCoder:aDecoder]; | ||
} | ||
// Require nib name is equal to class name | ||
UIView *view = [[self class] xx_loadFromNibWithOwner:owner]; | ||
|
||
objc_setAssociatedObject(view, kXXNibOwnerKey, owner, OBJC_ASSOCIATION_RETAIN_NONATOMIC); | ||
|
||
NSAssert(view, @"View of class [%@] could not load from nib, check whether the view in nib binds the correct class", [[self class] xx_nibID]); | ||
|
||
view.frame = self.frame; | ||
view.autoresizingMask = self.autoresizingMask; | ||
view.hidden = self.hidden; | ||
|
||
// Autolayout support | ||
if ([view respondsToSelector:@selector(translatesAutoresizingMaskIntoConstraints)]) | ||
{ | ||
view.translatesAutoresizingMaskIntoConstraints = NO; | ||
} | ||
|
||
// Autolayout constrains replacing | ||
// Replace all constrains from `placeholder(self)` view to `real` view | ||
if ([view respondsToSelector:@selector(constraints)] && self.constraints.count > 0) | ||
{ | ||
[self replaceAutolayoutConstrainsFromView:self toView:view]; | ||
} | ||
|
||
return view; | ||
} | ||
|
||
// Reset flag | ||
setIBReplaceFlag([self class], NO); | ||
|
||
return self; | ||
} | ||
|
||
- (void)replaceAutolayoutConstrainsFromView:(UIView *)placeholderView toView:(UIView *)realView | ||
{ | ||
// We only need to copy `self` constraints (like width/height constraints) | ||
// from placeholder to real view | ||
for (NSLayoutConstraint *constraint in placeholderView.constraints) | ||
{ | ||
NSLayoutConstraint* newConstraint = [NSLayoutConstraint constraintWithItem:realView | ||
attribute:constraint.firstAttribute | ||
relatedBy:constraint.relation | ||
toItem:nil // Only first item | ||
attribute:constraint.secondAttribute | ||
multiplier:constraint.multiplier | ||
constant:constraint.constant]; | ||
newConstraint.shouldBeArchived = constraint.shouldBeArchived; | ||
newConstraint.priority = constraint.priority; | ||
[realView addConstraint:newConstraint]; | ||
} | ||
} | ||
@end |